模拟:使用一个numpy数组断言嘲笑嘲笑作为参数引发ValueError和np.testing.assert_array_equal不起作用

时间:2019-06-18 08:21:30

标签: python unit-testing numpy mocking

我有一个模拟对象,我想使用模拟调用来检查其调用,其中使用 numpy arrays 进行调用。但是问题在于,它引发了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]))]

现在,我设置了预期的通话次数:

>>> expected_call_with_numpy = [mock.call(np.array([1, 2]))]

现在,如果我按如下所示进行检查,则会引发错误:

>>> 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:\users\meysam.sadeghi\appdata\local\programs\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()

我对stackoverflow的搜索以及找到的解决方案:

HERE建议您在拥有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:\users\meysam.sadeghi\appdata\local\programs\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:\users\meysam.sadeghi\appdata\local\programs\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)

请注意,数组是相同的,但是会产生错误!

任何人都可以评论如何对使用numpy数组调用的嘲笑对象使用嘲笑调用,然后检查嘲笑调用是否产生了预期的调用?例如,下面的

assert expected_call_with_numpy == mocked_model_called_with_np_array.mock_calls

3 个答案:

答案 0 :(得分:2)

遇到同样的问题,尝试检查模拟的调用是否包含特定的numpy数组。 事实证明调用对象是可索引的,因此您还可以执行以下操作:

>>> 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}

因此,您不必检查调用是否相等,而可以检查调用是否已通过,并且传递的参数分别正确,丑陋,但可以使用:

>>> 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
...

答案 1 :(得分:0)

只需创建一个伪(模拟)类,就可以跟踪传递给类的任何方法的numpy参数。例如,如果我要检查对类bar的对象的方法Foo的numpy调用,可以执行以下操作:

class MockFoo():
    called_by = []
    def bar(self, *args):
        self.called_by.extend([*args])

现在,我们有:

>>> a = MockFoo()
>>> a.bar(numpy.array([1, 2]))
>>> a.bar(numpy.array([100, 200]))
>>> a.bar(numpy.array([10000, 20000]))

现在,我们可以简单地检查对foo.bar的呼叫,如下所示:

>>> a.called_by 
[array([1, 2]), array([100, 200]), array([10000, 20000])]

答案 2 :(得分:0)

主要问题来自 numpy 覆盖 == 运算符,返回一个数组而不是单个布尔值。

不过,有一种方法可以解决这个问题。如果您使用 callee 库检查调用参数,则可以使用 callee.general.Matching 并提供 lambda 来检查相等性。

这是它如何与 np.allclose 一起使用

mocked_fn.assert_called_with(
  callee.general.Matching(lambda x: np.allclose(x, my_array))
)

注意:我与被调用库没有任何关联。