getattr()调用的Python模拟返回

eri*_*cso 5 python unit-testing mocking

编辑:我可能会落在这里的XY问题陷阱。这是我真正想知道的

我有以下功能:

def foo():
  bar = funcToGetBar()
  return bar.getattr("some_attr", None)
Run Code Online (Sandbox Code Playgroud)

在测试中,我尝试执行以下操作:

mocked_bar = MagicMock()
expected_return_val = [obj1, obj2, ...]
funcToGetBar.return_value = mocked_bar  # funcToGetBar is patched

def testGetBar(self):
  assertEqual(expected_return_val, foo())
Run Code Online (Sandbox Code Playgroud)

现在,我要做的是在对象expected_return_valsome_attr属性上提供bar

我尝试使用PropertyMock:

type(mocked_bar).getattr = PropertyMock(return_value=expected_return_value)
Run Code Online (Sandbox Code Playgroud)

运行测试我得到了错误:

TypeError: 'list' object is not callable
Run Code Online (Sandbox Code Playgroud)

如果将return_value设置为标量(而不是列表),则getattr在实函数中的调用结果是模拟的,而不是我提供的标量。

另外,我担心会模仿该getattr方法,因为它是一种通用方法,可能会在我的函数中的其他地方使用。如何在被测试的模拟对象的属性上设置列表?

小智 1

根据文档,Mock 的 return_value 不可迭代。要获得可迭代的 return_value,请使用 side_effect。

mocked_bar = MagicMock()
mocked_bar.side_effect = [obj1, obj2, ...]

Run Code Online (Sandbox Code Playgroud)

编辑:文档位于https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock

具体来说:

side_effect:每当调用 Mock 时都会调用的函数。请参阅 side_effect 属性。对于引发异常或动态更改返回值很有用。使用与模拟相同的参数调用该函数,除非它返回 DEFAULT,否则该函数的返回值将用作返回值。