用python编写一些单元测试,并使用MagicMock来模拟一个接受JSON字符串作为输入的方法。在我的单元测试中,我想断言它是用给定的参数调用的,但我在断言语句中遇到了问题,因为除了字符串的断言语句外,dict中对象的顺序无关紧要。下面是我试图实现的目标的简化示例。
mock_funct = MagicMock()
# mocked function called elsewhere
expected = {"a":"a", "b":"b"}
mock_funct.assert_called_once_with(json.dumps(expected))
当dict转储到json时,由于dict中键的任意顺序,上述内容可能通过,也可能失败,即'{"a":"a", "b":"b"}'
和'{"b":"b", "a":"a"}'
都是有效的转储,但其中一个会失败,另一个会通过,但我想编写测试,使两者都通过。
不幸的是,您需要在这里进行自己的检查。您可以通过mock的call_args_list
属性(或者,在本例中仅为call_args
,因为您已经断言它只被调用一次)从mock获取调用。我假设您在我的示例代码中使用unittest
,但它应该很容易适应任何测试框架。。。
mock_funct.assert_called_once_with(mock.ANY)
call = mock_funct.call_args
call_args, call_kwargs = call # calls are 2-tuples of (positional_args, keyword_args)
self.assertEqual(json.loads(call_args[0]), expected)
我仍然使用assert_called_once_with
来确保函数只被一个位置参数调用过一次,但随后我打开调用来查看该参数,以检查它是否正确。
在后台,unittest的assert_called_once_with
将对调用中的每个参数执行相等性检查。
Python有一个dunder方法来控制如何执行相等检查:__eq__
知道了这一点,我们可以创建一个包装类来帮助我们:
import json
class JsonChecker:
def __init__(self, value):
self.value = value
def __eq__(self, other):
return json.loads(other) == self.value
mock_funct.assert_called_once_with(JsonChecker(expected))