我正在使用pytest3.7进行测试。我想模拟res
,它是get_res_function
的返回值。 res.property1[key1][keyN].property2
是我要模拟的值。这是我的测试:
@mock.patch("mypkg.get_res_function")
def test_function(mock_res):
returner = mock.MagicMock()
returner.property1["key1"]["key2"].property2 = "11111"
returner.property1["key1"]["key3"].property2 = "22222"
mock_res.return_value = returner
但是,我要模拟的两个值仅使用第一行模拟的值,这意味着mock_res.property1["key1"]["key2"].property2 = "11111", mock_res_property1["key1"]["key3"].property2 = "11111"
并且如果在测试代码中将其反转,则意味着将“ 22222”放在“ 11111”之前,
returner.property1["key1"]["key2"].property2 = "22222"
returner.property1["key1"]["key3"].property2 = "11111"
那么所有结果都是“ 22222”,这是什么问题?
答案 0 :(得分:1)
这很棘手,因为项目访问语法thing[index]
实际上是在调用魔术方法__getitem__
,而这正是您要模拟的内容。
所以这个
returner.property1["key1"]["key2"].property2 = "11111"
喜欢这样做
returner.property1.__getitem__.return_value.__getitem__.return_value.property2 = "11111"
没关系,因为它更加简洁,但是实际上忽略了键。
您可以将PropertyMock
与side_effect
一起使用,以按顺序返回不同的内容:
type(returner.property1.__getitem__.return_value.__getitem__.return_value).property2 = PropertyMock(side_effect=["11111", "22222"])
或者,返回以获得项目语法:
type(returner.property1["this is"]["ignored"]).property2 = PropertyMock(side_effect=["11111", "22222"])
它应该可以工作:
returner.property1["foo"]["bar"].property2
> '11111'
returner.property1["foo"]["bar"].property2
> '22222'
但是,请记住,无论输入键如何,它将返回相同的值。如果用完StopIteration
,它将提高side_effects
。
您可以断言哪些键实际用于调用__getitem__
:
returner.property1.__getitem__.call_args_list
returner.property1.__getitem__.return_value.__getitem__.call_args_list
如果愿意,可以改为使用side_effect
作为函数,该函数将使用与模拟(键)相同的参数进行调用,然后可以根据键决定返回什么。但这需要在__getitem__
模拟中完成,而不是在属性模拟中完成。
一些参考文献: