我正在使用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"
如果在测试代码中反转它,这意味着在"11111"之前放置"22222",
returner.property1["key1"]["key2"].property2 = "22222"
returner.property1["key1"]["key3"].property2 = "11111"
那么所有的结果都是"22222",怎么了?
这很棘手,因为项目访问语法thing[index]
实际上是在调用魔术方法__getitem__
,这就是您想要模拟的。
所以这个
returner.property1["key1"]["key2"].property2 = "11111"
就像这样做一样
returner.property1.__getitem__.return_value.__getitem__.return_value.property2 = "11111"
这没关系,因为它更简洁一些,但是键实际上被忽略了。
您可以使用带有side_effect
的PropertyMock
按顺序返回不同的内容:
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'
但是,请记住,无论输入键如何,它都将返回相同的值。如果用完side_effects
,它会提高StopIteration
.
您可以断言哪些键实际用于调用__getitem__
:
returner.property1.__getitem__.call_args_list
returner.property1.__getitem__.return_value.__getitem__.call_args_list
如果您愿意,可以将函数作为side_effect
传递,而是使用与模拟(键(相同的参数调用它,然后您可以根据键决定返回什么。但这需要在__getitem__
模拟中完成,而不是在财产模拟中完成。
一些参考资料:
__getitem__
: https://docs.python.org/3/reference/datamodel.html#object。获取项PropertyMock
: https://docs.python.org/3/library/unittest.mock.html#unittest.mock.PropertyMockside_effect
: https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.side_effect