[英]Mock: assert mock_calls with a numpy array as argument raises ValueError and np.testing.assert_array_equal does not work
I have a mocked object that I would like to check its calls using mock_calls, where it is called with numpy arrays .我有一个模拟对象,我想使用 mock_calls 检查它的调用,其中使用numpy arrays调用它。 But the problem is that it raises ValueError, as shown in the following simple toy example.
但问题是它引发了 ValueError,如下面的简单玩具示例所示。
>>> mocked_model_called_with_np_array = mock.Mock()
>>> mocked_model_called_with_np_array(np.array([1, 2]))
>>> mocked_model_called_with_np_array.mock_calls
[call(array([1, 2]))]
Now I set the expected calls:现在我设置了预期的调用:
>>> expected_call_with_numpy = [mock.call(np.array([1, 2]))]
Now if I check it as shown below, it raises error:现在,如果我按如下所示进行检查,则会引发错误:
>>> assert expected_call_with_numpy == mocked_model_called_with_np_array.mock_calls
---------------------------------------------------------------------------
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-61-9806e62badf5> in <module>
----> 1 assert expected_call_with_numpy == mocked_model_called_with_np_array.mock_calls
c:\..\python\python36\lib\unittest\mock.py in __eq__(self, other)
2053
2054 # this order is important for ANY to work!
-> 2055 return (other_args, other_kwargs) == (self_args, self_kwargs)
2056
2057
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
My search on stackoverflow and the found solutions:我在 stackoverflow 上的搜索和找到的解决方案:
HERE it is suggested to use np.testing.assert_array_equal
while you have numpy arrays, but this also does not solve my problems as shown below. 这里建议在您拥有 numpy 数组时使用
np.testing.assert_array_equal
,但这也不能解决我的问题,如下所示。
>>> np.testing.assert_array_equal(expected_call_with_numpy, mocked_model_called_with_np_array.mock_calls)
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-57-4a0373c94354> in <module>
----> 1 np.testing.assert_array_equal(expected_call_with_numpy, mocked_model_called_with_np_array.mock_calls)
c:\...\python\python36\lib\site-packages\numpy\testing\utils.py in assert_array_equal(x, y, err_msg, verbose)
852 __tracebackhide__ = True # Hide traceback for py.test
853 assert_array_compare(operator.__eq__, x, y, err_msg=err_msg,
--> 854 verbose=verbose, header='Arrays are not equal')
855
856
c:\...\python\python36\lib\site-packages\numpy\testing\utils.py in assert_array_compare(comparison, x, y, err_msg, verbose, header, precision, equal_nan, equal_inf)
776 names=('x', 'y'), precision=precision)
777 if not cond:
--> 778 raise AssertionError(msg)
779 except ValueError:
780 import traceback
AssertionError:
Arrays are not equal
(mismatch 100.0%)
x: array([['', (array([1, 2]),), {}]], dtype=object)
y: array([['', (array([1, 2]),), {}]], dtype=object)
Note that the arrays are the same, but it produces error!请注意,数组是相同的,但会产生错误!
Can anyone comment on how to use mock_calls for a mockec object called with a numpy array and then check if the mock_calls produce the expected calls?任何人都可以评论如何将 mock_calls 用于使用 numpy 数组调用的 mockec 对象,然后检查 mock_calls 是否产生预期的调用? eg, something like below
例如,像下面这样
assert expected_call_with_numpy == mocked_model_called_with_np_array.mock_calls
Ran in to the same problem trying to check if mocked calls contained a specific numpy array.尝试检查模拟调用是否包含特定的 numpy 数组时遇到了同样的问题。 Turns out that the call object is indexable so you can also do stuff like this:
结果是调用对象是可索引的,所以你也可以做这样的事情:
>>> import numpy as np
>>> from unittest import mock
>>> mock_object = mock.MagicMock()
>>> mock_object(1, np.array([1, 2, 3]), a=3)
>>> mock_object(10, np.array([10, 20, 30]), b=30)
>>> calls = mock_object.call_args_list
>>> calls
[call(1, array([1, 2, 3]), a=3), call(10, array([10, 20, 30]), b=30)]
>>> calls[0]
call(1, array([1, 2, 3]), a=3)
>>> calls[0][0]
(1, array([1, 2, 3]))
>>> calls[0][1]
{'a': 3}
So that instead of asserting that the calls are equal you can just check that the calls were made and that arguments passed were correct individually, ugly but it works:因此,与其断言调用是相等的,您只需检查调用是否进行以及传递的参数是否单独正确,虽然丑陋,但它有效:
>>> assert mock_object.call_count == 2
>>> assert calls[0][0][0] == 1
>>> np.testing.assert_array_equal(calls[0][0][1], np.array([1, 2, 3]))
>>> assert calls[0][1]['a'] == 3
...
One can track the numpy arguments passed to any method of a class, simply by creating a fake (mock) class.只需创建一个假(模拟)类,就可以跟踪传递给类的任何方法的 numpy 参数。 For example, if I want to check the numpy calls to method
bar
of an object of class Foo
, I can do as follows:例如,如果我想检查对
Foo
类对象的方法bar
的 numpy 调用,我可以执行以下操作:
class MockFoo():
called_by = []
def bar(self, *args):
self.called_by.extend([*args])
Now, we have:现在,我们有:
>>> a = MockFoo()
>>> a.bar(numpy.array([1, 2]))
>>> a.bar(numpy.array([100, 200]))
>>> a.bar(numpy.array([10000, 20000]))
Now we can simply check the calls to foo.bar
as below:现在我们可以简单地检查对
foo.bar
的调用,如下所示:
>>> a.called_by
[array([1, 2]), array([100, 200]), array([10000, 20000])]
The main problem comes from numpy overriding ==
operator, returning an array instead of single boolean value.主要问题来自 numpy 覆盖
==
运算符,返回一个数组而不是单个布尔值。
There is a way around that, though.不过,有一种方法可以解决这个问题。 If you use callee library to check call arguments, you can use callee.general.Matching and provide a lambda to check equality.
如果您使用callee库来检查调用参数,则可以使用 callee.general.Matching 并提供一个 lambda 来检查相等性。
Here's how it works with np.allclose这是它如何与 np.allclose 一起使用
mocked_fn.assert_called_with(
callee.general.Matching(lambda x: np.allclose(x, my_array))
)
Note: I'm not associated with callee library in any way.注意:我与被调用库没有任何关联。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.