2016-07-12 25 views
7

Tôi đã cố gắng thực hiện một số kiểm tra đơn vị cho một mô-đun. Một module ví dụ đặt tên alphabet.py là như sau:Mocking một biến toàn cầu

import database 

def length_letters(): 
    return len(letters) 

def contains_letter(letter): 
    return True if letter in letters else False 


letters = database.get('letters') # returns a list of letters 

Tôi muốn thử phản ứng từ một cơ sở dữ liệu với một số giá trị của sự lựa chọn của tôi, nhưng mã dưới đây dường như không làm việc.

import unittests 
import alphabet 
from unittest.mock import patch 


class TestAlphabet(unittest.TestCase): 
    @patch('alphabet.letters') 
    def setUp(self, mock_letters): 
     mock_letters.return_value = ['a', 'b', 'c'] 

    def test_length_letters(self): 
     self.assertEqual(3, alphabet.length_letters()) 

    def test_contains_letter(self): 
     self.assertTrue(alphabet.contains_letter('a')) 

Tôi đã thấy nhiều ví dụ trong đó 'vá' được áp dụng cho các phương pháp và lớp học, nhưng không áp dụng cho các biến. Tôi không muốn vá phương thức database.get vì tôi có thể sử dụng lại nó với các thông số khác nhau sau này, vì vậy tôi sẽ cần một phản hồi khác.

Tôi đang làm gì sai ở đây?

Trả lời

2

Bạn không cần sử dụng mô hình. Chỉ cần nhập các mô-đun và thay đổi giá trị của toàn cầu trong vòng setUp():

import alphabet 

class TestAlphabet(unittest.TestCase): 
    def setUp(self): 
     alphabet.letters = ['a', 'b', 'c'] 
+3

Một hậu quả không may của phương pháp này là bất kỳ thử nghiệm nào khác sử dụng biến cấp mô-đun này sẽ thất bại trừ khi bạn lưu trữ giá trị cũ và đặt lại. Mocking sẽ chăm sóc điều này cho bạn. –

+1

Bạn có thể đặt giá trị của 'alphabet.letters' trở lại thành giá trị trong hàm' tearDown'. – tomas

+0

Ngoài ra, vì 'setUp' được đưa vào toàn bộ lớp thử nghiệm, bạn chỉ có thể sử dụng một giá trị này cho' chữ cái'. Câu trả lời của Will dưới đây cho phép bạn thực hiện nhiều mocks cho các trường hợp thử nghiệm khác nhau, và chúng tự làm sạch chính mình vào cuối để không có nguy cơ ô nhiễm kiểm tra ngẫu nhiên. – raindrift

10

Hãy thử điều này:

import unittests 
import alphabet 
from unittest.mock import patch 


class TestAlphabet(unittest.TestCase): 
    def setUp(self): 
     self.mock_letters = mock.patch.object(
      alphabet, 'letters', return_value=['a', 'b', 'c'] 
     ) 

    def test_length_letters(self): 
     with self.mock_letters: 
      self.assertEqual(3, alphabet.length_letters()) 

    def test_contains_letter(self): 
     with self.mock_letters: 
      self.assertTrue(alphabet.contains_letter('a')) 

Bạn cần phải áp dụng các mô hình trong khi các bài kiểm tra cá nhân đang thực sự chạy, không chỉ ở setUp(). Chúng tôi có thể tạo mô hình trong setUp() và áp dụng sau với một Trình quản lý ngữ cảnh with ....

+0

Đây là những gì tôi đã yêu cầu, nhưng câu trả lời của John có vẻ tốt hơn cho ví dụ được đưa ra. Tôi thấy bạn hữu ích cho các trường hợp khác mặc dù. Cảm ơn bạn. – Funkatic

+0

Không sao, vui lòng trợ giúp! – Will

0

Tôi gặp phải vấn đề mà tôi đang cố gắng thử các biến được sử dụng bên ngoài bất kỳ hàm hoặc lớp nào, điều này có vấn đề vì chúng được sử dụng vào lúc bạn cố gắng thử lớp, trước khi bạn có thể thử các giá trị.

Tôi đã sử dụng biến môi trường. Nếu biến môi trường tồn tại, sử dụng giá trị đó, nếu không thì hãy sử dụng ứng dụng mặc định. Bằng cách này tôi có thể thiết lập giá trị biến môi trường trong các thử nghiệm của tôi.

Trong thử nghiệm của tôi, tôi đã có mã này trước khi lớp học đã được nhập khẩu

os.environ["PROFILER_LOG_PATH"] = "./" 

Trong lớp học của tôi:

log_path = os.environ.get("PROFILER_LOG_PATH",config.LOG_PATH) 

Theo mặc định của tôi config.LOG_PATH/var/log/<my app name>, nhưng bây giờ khi thử nghiệm đang chạy, đường dẫn đăng nhập được đặt thành thư mục hiện tại. Bằng cách này bạn không cần quyền truy cập root để chạy thử nghiệm.

+1

Lý tưởng nhất là các thử nghiệm của bạn phải giống hệt nhau trên mọi môi trường, không có bất kỳ cấu hình bổ sung nào. Nếu không, họ có thể vượt qua trên máy địa phương của bạn nhưng thất bại ở một nơi khác. – Funkatic