모의 메소드에 대한 연속 호출 주장
모의에게 유용한 assert_called_with()
방법이 있습니다. 그러나 내가 이해 하는 한 메소드에 대한 마지막 호출 만 확인합니다 .
매번 다른 매개 변수를 사용하여 mocked 메서드를 3 번 연속적으로 호출하는 코드가있는 경우 특정 매개 변수를 사용 하여이 3 호출을 어설 션하려면 어떻게해야합니까?
assert_has_calls
이 문제에 대한 또 다른 접근법입니다.
문서에서 :
assert_has_calls (호출, any_order = False)
지정된 호출로 모의가 호출되었다고 주장하십시오. mock_calls 목록에서 호출을 확인합니다.
any_order가 False (기본값)이면 호출은 순차적이어야합니다. 지정된 통화 전후에 추가 통화가있을 수 있습니다.
any_order가 True이면 호출 순서는 상관 없지만 모두 mock_calls에 나타나야합니다.
예:
>>> from mock import call, Mock
>>> mock = Mock(return_value=None)
>>> mock(1)
>>> mock(2)
>>> mock(3)
>>> mock(4)
>>> calls = [call(2), call(3)]
>>> mock.assert_has_calls(calls)
>>> calls = [call(4), call(2), call(3)]
>>> mock.assert_has_calls(calls, any_order=True)
출처 : https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.assert_has_calls
보통, 나는 통화 순서에 신경 쓰지 않고 단지 그들이 일어난 일에만 신경 쓰지 않습니다. 이 경우에 assert_any_call
대한 어설 션과 결합 call_count
합니다.
>>> import mock
>>> m = mock.Mock()
>>> m(1)
<Mock name='mock()' id='37578160'>
>>> m(2)
<Mock name='mock()' id='37578160'>
>>> m(3)
<Mock name='mock()' id='37578160'>
>>> m.assert_any_call(1)
>>> m.assert_any_call(2)
>>> m.assert_any_call(3)
>>> assert 3 == m.call_count
>>> m.assert_any_call(4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "[python path]\lib\site-packages\mock.py", line 891, in assert_any_call
'%s call not found' % expected_string
AssertionError: mock(4) call not found
단일 메서드에 전달 된 많은 호출 목록보다 읽기 쉽고 이해하기 쉽도록이 방법을 사용합니다.
주문에 관심이 있거나 동일한 전화가 여러 번 예상되는 assert_has_calls
것이 더 적절할 수 있습니다.
편집하다
이 답변을 게시 한 이후 일반적인 테스트 방법을 다시 생각했습니다. 테스트가 복잡해지면 부적절하게 테스트 중이거나 디자인에 문제가있을 수 있습니다. Mocks는 객체 지향 디자인에서 객체 간 통신을 테스트하도록 설계되었습니다. 디자인이 객체 지향적이지 않은 경우 (더 절차 적 또는 기능적) 모의는 완전히 부적절 할 수 있습니다. 메소드 내부에서 너무 많은 일이 발생했거나 가장 잘 조롱되지 않은 내부 세부 사항을 테스트하는 중일 수 있습니다. 내 코드가 객체 지향적이지 않을 때이 방법에서 언급 된 전략을 개발했으며, 가장 잘 드러나지 않은 내부 세부 정보도 테스트하고 있다고 생각합니다.
이 Mock.call_args_list
속성 을 사용하여 매개 변수를 이전 메소드 호출과 비교할 수 있습니다 . Mock.call_count
속성 과 함께 모든 권한을 부여해야합니다.
나는 항상 이것을 한 번에 다시 찾아야하므로 여기에 내 대답이 있습니다.
같은 클래스의 다른 객체에 대해 여러 개의 메소드 호출
우리가 무거운 클래스를 가지고 있다고 가정 해보십시오 (우리가 조롱하고 싶어).
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))
...:
다음은 HeavyDuty
클래스의 두 인스턴스를 사용하는 코드입니다 .
In [2]: def heavy_work():
...: hd1 = HeavyDuty()
...: hd1.do_work(13, 17)
...: hd2 = HeavyDuty()
...: hd2.do_work(23, 29)
...:
이제 heavy_work
함수에 대한 테스트 사례가 있습니다.
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)
...:
We are mocking the HeavyDuty
class with MockHeavyDuty
. To assert method calls coming from every HeavyDuty
instance we have to refer to MockHeavyDuty.return_value.assert_has_calls
, instead of MockHeavyDuty.assert_has_calls
. In addition, in the list of expected_calls
we have to specify which method name we are interested in asserting calls for. So our list is made of calls to call.do_work
, as opposed to simply call
.
Exercising the test case shows us it is successful:
In [4]: print(test_heavy_work())
None
If we modify the heavy_work
function, the test fails and produces a helpful error message:
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)]
Asserting multiple calls to a function
To contrast with the above, here is an example that shows how to mock multiple calls to a function:
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
There are two main differences. The first one is that when mocking a function we setup our expected calls using call
, instead of using call.some_method
. The second one is that we call assert_has_calls
on mock_work_function
, instead of on mock_work_function.return_value
.
참고URL : https://stackoverflow.com/questions/7242433/asserting-successive-calls-to-a-mock-method
'Programing' 카테고리의 다른 글
postgresql COUNT (DISTINCT…) 매우 느림 (0) | 2020.06.25 |
---|---|
대화 형 Python 셸에서 마지막 결과 얻기 (0) | 2020.06.25 |
동적으로 작성된 입력에 대해 jQuery .on ( 'change', function () {}이 트리거되지 않음 (0) | 2020.06.25 |
Selenium Webdriver가 백그라운드에서 자동으로 브라우저 창을 열 수 있습니까? (0) | 2020.06.25 |
span 또는 div 래핑 방지 (0) | 2020.06.24 |