简体   繁体   English

检查是否已使用不同参数多次调用函数

[英]Checking whether function has been called multiple times with different parameters

Assume we have a function f(x,y) and another function 假设我们有一个函数f(x,y)和另一个函数

def g():
       # ...
       f(i,j) # i,j vary and f is called multiple times
       # ...

We want to write a Unit test that checks whether f is called the number of times and with the right parameters. 我们想要编写一个单元测试,检查f是否被称为次数和正确的参数。

def test_g():
      with patch('mymodule.f') as function:
          assert function.gacs.call_count == correct_no_calls

There is

function.assert_called_with(...)

but this only refers to the last call. 但这只是指最后一次通话。 So assuming g calls f(1,2) and then f(2,3) , function.assert_called_with(1,2) is False . 假设g调用f(1,2)然后调用f(1,2) f(2,3) ,则function.assert_called_with(1,2)False

Furthermore, there is 此外,还有

function.call_args_list

which yields a list of call objects with the right parameters. 它产生一个具有正确参数的call对象列表。 Comparing this list to call object that we create in the unit test feels like a very nasty thing to do. 将此列表与我们在单元测试中创建的call对象进行比较感觉就像是一件非常讨厌的事情。 call seems like an internal class of the mock library. call看起来像是mock库的内部类。

Is there a better way to do this? 有一个更好的方法吗? I use this set-up to test parallel execution of an apply function. 我使用此设置来测试apply函数的并行执行。

Even @MartinPieters's answer is correct I think that is not the best way to do it. 即使@ MartinPieters的答案是正确的,我认为这不是最好的方法。 Mock provide assert_has_calls to do this kind of duties. 模拟提供assert_has_calls来履行这种职责。

Your test could be: 你的测试可能是:

function.assert_has_calls([mock.call(1, 2), mock.call(2, 3)])

Where mock.call is a helper class do to these kind of jobs. mock.call是帮助类对这些工作做的事情。

Pay attention that is a has call and means the call list should be in the list of call and not equal. 注意这是一个呼叫,意味着呼叫列表应该在呼叫列表中并且不相等。 To solve it I usually define my own helper assert_is_calls() as follow 为了解决这个问题,我通常会定义自己的帮助程序assert_is_calls() ,如下所示

def assert_is_calls(m, calls, any_order=False):
   assert len(m.mock_calls) == len(calls)
   m.assert_has_calls(calls, any_order=any_order)

That a resume example 那是一个简历的例子

>>> import mock
>>> f = mock.Mock()
>>> f(1)
<Mock name='mock()' id='139836302999952'>
>>> f(2)
<Mock name='mock()' id='139836302999952'>
>>> f.assert_has_calls([mock.call(1), mock.call(2)])
>>> f.assert_has_calls([mock.call(2), mock.call(1)])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/damico/.local/lib/python2.7/site-packages/mock/mock.py", line 969, in assert_has_calls
    ), cause)
  File "/home/damico/.local/lib/python2.7/site-packages/six.py", line 718, in raise_from
    raise value
AssertionError: Calls not found.
Expected: [call(2), call(1)]
Actual: [call(1), call(2)]
>>> f.assert_has_calls([mock.call(2), mock.call(1)], any_order=True)
>>> f(3)
<Mock name='mock()' id='139836302999952'>
>>> f.assert_has_calls([mock.call(2), mock.call(1)], any_order=True)
>>> f.assert_has_calls([mock.call(1), mock.call(2)])
>>> assert len(f.mock_calls)==2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError
>>> assert len(f.mock_calls)==3
>>> def assert_is_calls(m, calls, any_order=False):
...    assert len(m.mock_calls) == len(calls)
...    m.assert_has_calls(calls, any_order=any_order)
... 
>>> assert_is_calls(f, [mock.call(1), mock.call(2), mock.call(3)])
>>> assert_is_calls(f, [mock.call(1), mock.call(3), mock.call(2)])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in assert_is_calls
  File "/home/damico/.local/lib/python2.7/site-packages/mock/mock.py", line 969, in assert_has_calls
    ), cause)
  File "/home/damico/.local/lib/python2.7/site-packages/six.py", line 718, in raise_from
    raise value
AssertionError: Calls not found.
Expected: [call(1), call(3), call(2)]
Actual: [call(1), call(2), call(3)]
>>> assert_is_calls(f, [mock.call(1), mock.call(3), mock.call(2)], True)
>>> assert_is_calls(f, [mock.call(1), mock.call(3)], True)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in assert_is_calls
AssertionError
>>> 

Test if the Mock().mock_calls list is equal to a list of mock.call() objects you provide: 测试Mock().mock_calls列表是否等于您提供的mock.call()对象列表:

self.assertEquals(function.mock_calls, [
    mock.call(1, 2),
    mock.call(2, 3),
])

This gives you precise control, requiring both the order and the number of calls to match. 这为您提供了精确控制,同时要求匹配的顺序和呼叫数量。

The mock.call() class is not internal, it is meant to be used for assertions like these. mock.call()类不是内部的,它意味着用于这样的断言。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM