【发布时间】:2016-04-02 17:06:56
【问题描述】:
我有这个生产类:
class MyClass:
def __init__(self):
self.value = None
def set_value(self, value):
self.value = value
def foo(self):
# work with self.value here
# raise RuntimeError("error!")
return "a"
这是从另一个地方使用的,像这样:
class Caller:
def bar(self, smth):
obj = MyClass()
obj.set_value(smth)
# ...
# try:
obj.foo()
# except MyError:
# pass
obj.set_value("str2")
# obj.foo()
我得到了这个:
class MyError(Exception):
pass
在我的测试中,我想确保 Caller.bar 调用 obj.set_value,首先使用 smth="a",然后使用 smth="b",但我希望它真正设置值(即调用真实的set_value 方法)。有什么办法让我告诉 mock 使用实际的方法,以便我以后可以阅读它的调用方法?
附:我知道我可以将“foo”更改为需要参数“smth”,这样我就可以摆脱“set_value”,但我想知道是否还有其他选项。
好的,所以我在我的测试中尝试了这个:
def test_caller(self):
with patch('fullpath.to.MyClass', autospec=MyClass) as mock:
mock.foo.side_effect = [MyError("msg"), "text"]
caller = Caller()
caller.bar("str1")
calls = [call("str1"), call("str2")]
mock.set_value.assert_has_calls(calls)
但我看到模拟没有成功,因为当我希望它首先引发 MyError,然后返回“text”时调用真正的“foo”。
另外,断言失败:
AssertionError: Calls not found.
Expected: [call('str1'), call('str2')]
Actual: []
【问题讨论】:
-
您是否阅读过模拟和单元测试文档?这绝对是可行的。 SO上有几个关于这个的例子。您是否有任何可以共享的单元测试代码来帮助您解决遇到的困难?
-
我仍然打开标签查看它,但我看到的只是对模拟的“调用”的调用。如果我使用“with patch.object(MyClass, 'set_value') as mock_fetch:”,mock_fetch 将......好吧,替换我的方法。
-
这不是很有帮助。请修改您的问题并提供您的单元测试代码的minimal reproducible example。
-
但是如果你在测试
Caller,你就不是在测试MyClass。你确定你不能完全模拟MyClass吗? -
这可能是个好主意...我对python很陌生,对python的模拟也很陌生...如果我只为MyClass使用MagicMock,那么我应该能够调用 my_magic_mock.set_value.assert_has_calls()。这应该可以清除我的测试代码中的许多“with patch(...)”-es。
标签: python python-3.x mocking