Tôi luôn phải tìm cái này hết lần này đến lần khác, vì vậy đây là câu trả lời của tôi.
Khẳng định nhiều cuộc gọi phương thức trên các đối tượng khác nhau của cùng một lớp
Giả sử chúng ta có một lớp nhiệm vụ nặng nề (mà chúng ta muốn chế giễu):
In [1]: class HeavyDuty(object):
...: def __init__(self):
...: import time
...: time.sleep(2) # <- Spends a lot of time here
...:
...: def do_work(self, arg1, arg2):
...: print("Called with %r and %r" % (arg1, arg2))
...:
đây là một số mã sử dụng hai thể hiện của HeavyDutylớp:
In [2]: def heavy_work():
...: hd1 = HeavyDuty()
...: hd1.do_work(13, 17)
...: hd2 = HeavyDuty()
...: hd2.do_work(23, 29)
...:
Bây giờ, đây là một trường hợp thử nghiệm cho heavy_workchức năng:
In [3]: from unittest.mock import patch, call
...: def test_heavy_work():
...: expected_calls = [call.do_work(13, 17),call.do_work(23, 29)]
...:
...: with patch('__main__.HeavyDuty') as MockHeavyDuty:
...: heavy_work()
...: MockHeavyDuty.return_value.assert_has_calls(expected_calls)
...:
Chúng tôi đang chế giễu HeavyDutylớp học với MockHeavyDuty. Để khẳng định các cuộc gọi phương thức đến từ mọi HeavyDutytrường hợp chúng ta phải tham khảo MockHeavyDuty.return_value.assert_has_calls, thay vì MockHeavyDuty.assert_has_calls. Ngoài ra, trong danh sách expected_callschúng tôi phải chỉ định tên phương thức mà chúng tôi quan tâm để xác nhận các cuộc gọi. Vì vậy, danh sách của chúng tôi được thực hiện các cuộc gọi đếncall.do_work , trái ngược với đơn giản call.
Thực hiện trường hợp thử nghiệm cho chúng ta thấy nó thành công:
In [4]: print(test_heavy_work())
None
Nếu chúng tôi sửa đổi heavy_workchức năng, kiểm tra thất bại và tạo ra một thông báo lỗi hữu ích:
In [5]: def heavy_work():
...: hd1 = HeavyDuty()
...: hd1.do_work(113, 117) # <- call args are different
...: hd2 = HeavyDuty()
...: hd2.do_work(123, 129) # <- call args are different
...:
In [6]: print(test_heavy_work())
---------------------------------------------------------------------------
(traceback omitted for clarity)
AssertionError: Calls not found.
Expected: [call.do_work(13, 17), call.do_work(23, 29)]
Actual: [call.do_work(113, 117), call.do_work(123, 129)]
Khẳng định nhiều cuộc gọi đến một chức năng
Để tương phản với điều trên, đây là một ví dụ cho thấy cách giả định nhiều cuộc gọi đến một chức năng:
In [7]: def work_function(arg1, arg2):
...: print("Called with args %r and %r" % (arg1, arg2))
In [8]: from unittest.mock import patch, call
...: def test_work_function():
...: expected_calls = [call(13, 17), call(23, 29)]
...: with patch('__main__.work_function') as mock_work_function:
...: work_function(13, 17)
...: work_function(23, 29)
...: mock_work_function.assert_has_calls(expected_calls)
...:
In [9]: print(test_work_function())
None
Có hai sự khác biệt chính. Đầu tiên là khi chế nhạo một chức năng, chúng tôi sẽ thiết lập các cuộc gọi dự kiến bằng cách sử dụng call, thay vì sử dụng call.some_method. Điều thứ hai là chúng ta gọi assert_has_callsvề mock_work_function, thay vì trên mock_work_function.return_value.