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

Python 检查是否已使用不同参数多次调用函数,python,unit-testing,testing,mocking,Python,Unit Testing,Testing,Mocking,假设我们有一个函数f(x,y)和另一个函数 def g(): # ... f(i,j) # i,j vary and f is called multiple times # ... 我们想编写一个单元测试,检查f是否调用了正确的次数和参数 def test_g(): with patch('mymodule.f') as function: assert function.gacs.call_count == corr

假设我们有一个函数
f(x,y)
和另一个函数

def g():
       # ...
       f(i,j) # i,j vary and f is called multiple times
       # ...
我们想编写一个单元测试,检查
f
是否调用了正确的次数和参数

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

function.assert_called_with(...)
但这只是指最后一次通话。因此,假设
g
调用
f(1,2)
然后
f(2,3)
函数.assert_called_with(1,2)
False

此外,还有

function.call_args_list
这将生成具有正确参数的
call
对象列表。将此列表与我们在单元测试中创建的
call
对象进行比较感觉是一件非常讨厌的事情<代码>调用似乎是模拟库的一个内部类

有更好的方法吗?我使用此设置来测试
apply
函数的并行执行。

测试是否等于您提供的列表:

self.assertEquals(function.mock_calls, [
    mock.call(1, 2),
    mock.call(2, 3),
])
这为您提供了精确的控制,需要同时匹配调用的顺序和数量


mock.call()
类不是内部的,它用于类似的断言。

即使@MartinPieters的答案是正确的,我认为这不是最好的方法。我可以提供这样的职责

您的测试可以是:

function.assert_has_calls([mock.call(1, 2), mock.call(2, 3)])
助手类在哪里处理这些工作

请注意,具有呼叫,这意味着呼叫列表应位于呼叫列表中,且不相等。为了解决这个问题,我通常定义自己的助手
assert\u is\u 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)
这是一个简历的例子

>>> 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
>>> 
导入模拟 >>>f=mock.mock() >>>f(1) >>>f(2) >>>断言有调用([mock.call(1),mock.call(2)]) >>>断言有调用([mock.call(2),mock.call(1)]) 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 文件“/home/damico/.local/lib/python2.7/site packages/mock/mock.py”,assert\u has\u调用中的第969行 ),原因) 文件“/home/damico/.local/lib/python2.7/site packages/six.py”,第718行,从 增值 AssertionError:找不到调用。 预期:[调用(2),调用(1)] 实际:[调用(1)和调用(2)] >>>断言有调用([mock.call(2),mock.call(1)],任意顺序=True) >>>f(3) >>>断言有调用([mock.call(2),mock.call(1)],任意顺序=True) >>>断言有调用([mock.call(1),mock.call(2)]) >>>断言len(f.mock_调用)==2 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 断言错误 >>>断言len(f.mock_调用)==3 >>>def assert_is_调用(m,调用,任意顺序=False): ... 断言len(m.mock_调用)=len(调用) ... m、 断言\u有\u调用(调用,任意\u顺序=任意\u顺序) ... >>>断言是调用(f,[mock.call(1)、mock.call(2)、mock.call(3)]) >>>断言是调用(f,[mock.call(1)、mock.call(3)、mock.call(2)]) 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 assert\u is\u调用中第3行的文件“” 文件“/home/damico/.local/lib/python2.7/site packages/mock/mock.py”,assert\u has\u调用中的第969行 ),原因) 文件“/home/damico/.local/lib/python2.7/site packages/six.py”,第718行,从 增值 AssertionError:找不到调用。 预期:[呼叫(1)、呼叫(3)、呼叫(2)] 实际:[调用(1)、调用(2)、调用(3)] >>>断言是调用(f,[mock.call(1),mock.call(3),mock.call(2)],True) >>>断言是调用(f,[mock.call(1),mock.call(3)],True) 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 assert\u is\u调用中第2行的文件“” 断言错误 >>>
assert\u has\u calls
不关心所有调用。您可以向它提供一个子集,它将返回true。如果您想断言这些是唯一的调用,那么您需要使用我的方法。您的包装器函数将
any\u order=False
保留为默认值,有效地执行与
assertEquals(m.mock\u calls,calls)
相同的操作,那么为什么要使用额外的函数呢?该函数不会为您购买任何额外的东西。@MartijnPieters是的,这是因为我提到了我自己的助手
assert\u is\u calls()
来关心所有调用。。。。我现在正在读你的新评论:都是关于命名的。这很清楚你想断言什么。无论如何,您可以选择您想要做的事情,检查顺序与否,检查所有调用或只是一个子集。@MartijnPieters只有一件事。OP没有说他想按照正确的顺序检查(或者我遗漏了什么?)。所以我涵盖了所有的可能性。