Bạn đã đúng, các bài kiểm tra của bạn không nên xác minh rằng random
mô-đun đang thực hiện công việc của nó; một unittest chỉ nên kiểm tra chính lớp đó, chứ không phải cách nó tương tác với mã khác (cần được kiểm tra riêng).
Tất nhiên là hoàn toàn có thể mã của bạn sử dụng random.randint()
sai; hoặc bạn đang gọi random.randrange(1, self._sides)
thay vào đó và cái chết của bạn không bao giờ ném giá trị cao nhất, nhưng đó là một loại lỗi khác, không phải là lỗi mà bạn có thể mắc phải với một lỗi nhỏ nhất. Trong trường hợp đó, die
đơn vị của bạn đang làm việc như thiết kế, nhưng bản thân thiết kế đã bị lỗi.
Trong trường hợp này, tôi muốn sử dụng chế giễu để thay thế các randint()
chức năng, và chỉ xác nhận rằng nó đã được gọi một cách chính xác. Python 3.3 trở lên đi kèm với unittest.mock
mô-đun để xử lý loại thử nghiệm này, nhưng bạn có thể cài đặt mock
gói bên ngoài trên các phiên bản cũ hơn để có được chức năng chính xác tương tự
import unittest
try:
from unittest.mock import patch
except ImportError:
# < python 3.3
from mock import patch
@patch('random.randint', return_value=3)
class TestDice(unittest.TestCase):
def _make_one(self, *args, **kw):
from die import Die
return Die(*args, **kw)
def test_standard_size(self, mocked_randint):
die = self._make_one()
result = die.roll()
mocked_randint.assert_called_with(1, 6)
self.assertEqual(result, 3)
def test_custom_size(self, mocked_randint):
die = self._make_one(sides=42)
result = die.roll()
mocked_randint.assert_called_with(1, 42)
self.assertEqual(result, 3)
if __name__ == '__main__':
unittest.main()
Với chế độ chế giễu, bài kiểm tra của bạn bây giờ rất đơn giản; chỉ có 2 trường hợp Trường hợp mặc định cho khuôn 6 mặt và trường hợp mặt tùy chỉnh.
Có nhiều cách khác để tạm thời thay thế randint()
hàm trong không gian tên toàn cục Die
, nhưng mock
mô-đun làm cho việc này dễ nhất. Trình @mock.patch
trang trí ở đây áp dụng cho tất cả các phương pháp thử nghiệm trong trường hợp thử nghiệm; mỗi phương thức kiểm tra được thông qua một đối số phụ, random.randint()
hàm giả định, vì vậy chúng ta có thể kiểm tra đối với bản giả để xem liệu nó có thực sự được gọi đúng không. Đối return_value
số chỉ định những gì được trả về từ giả khi nó được gọi, vì vậy chúng tôi có thể xác minh rằng die.roll()
phương thức thực sự trả về kết quả 'ngẫu nhiên' cho chúng tôi.
Tôi đã sử dụng một thực hành tốt nhất khác của Python ở đây: nhập lớp đang kiểm tra như một phần của bài kiểm tra. Các _make_one
phương pháp thực hiện việc nhập khẩu và instantiation làm việc trong một thử nghiệm , do đó kiểm tra mô-đun vẫn sẽ được tải ngay cả khi bạn đã thực hiện một lỗi cú pháp hoặc sai lầm khác mà sẽ ngăn chặn các mô-đun ban đầu để nhập khẩu.
Bằng cách này, nếu bạn đã mắc lỗi trong chính mã mô-đun, các bài kiểm tra sẽ vẫn được chạy; họ sẽ thất bại, nói với bạn về lỗi trong mã của bạn.
Để rõ ràng, các bài kiểm tra trên là đơn giản trong cực đoan. Mục tiêu ở đây không phải là kiểm tra mà random.randint()
đã được gọi với các đối số đúng, chẳng hạn. Thay vào đó, mục tiêu là kiểm tra xem đơn vị đó có tạo ra kết quả đúng với các đầu vào nhất định không, trong đó các đầu vào đó bao gồm kết quả của các đơn vị khác không được thử nghiệm. Bằng cách chế nhạo random.randint()
phương thức bạn có thể kiểm soát chỉ một đầu vào khác cho mã của bạn.
Trong các thử nghiệm trong thế giới thực , mã thực tế trong bài kiểm tra đơn vị của bạn sẽ phức tạp hơn; mối quan hệ với các đầu vào được truyền cho API và cách các đơn vị khác được gọi có thể vẫn thú vị và việc chế giễu sẽ cung cấp cho bạn quyền truy cập vào kết quả trung gian, cũng như cho phép bạn đặt giá trị trả về cho các cuộc gọi đó.
Ví dụ: trong mã xác thực người dùng với dịch vụ OAuth2 của bên thứ 3 (tương tác nhiều giai đoạn), bạn muốn kiểm tra xem mã của bạn có truyền đúng dữ liệu cho dịch vụ bên thứ 3 đó không và cho phép bạn giả mạo các phản hồi lỗi khác nhau mà Dịch vụ bên thứ 3 sẽ quay trở lại, cho phép bạn mô phỏng các kịch bản khác nhau mà không phải tự mình xây dựng máy chủ OAuth2. Ở đây, điều quan trọng là phải kiểm tra thông tin từ phản hồi đầu tiên đã được xử lý chính xác và đã được chuyển sang cuộc gọi ở giai đoạn thứ hai, vì vậy bạn muốn thấy rằng dịch vụ giả được gọi là chính xác.