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 HeavyDuty
lớ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_work
chứ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 HeavyDuty
lớp học với MockHeavyDuty
. Để khẳng định các cuộc gọi phương thức đến từ mọi HeavyDuty
trườ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_calls
chú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_work
chứ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_calls
về mock_work_function
, thay vì trên mock_work_function.return_value
.