我正在测试一个相对简单的代码,该代码使用两个需要磁盘访问的相对复杂的对象。复杂对象来自库。我想模拟这些库对象,并断言它们的某些成员函数是根据输入的特定值来调用的。
我使用的调用依赖于库对象的某些内部状态。我知道我可以单独模拟复杂对象上的每个函数调用,并在每个对象之前设置return_value
。但是,这似乎比需要的更加混乱和痛苦。
似乎您应该能够提供一个自定义类,并用Mock对象包装它,以跟踪对成员函数的所有调用。我花了几个小时试图弄清official documentation,发现的最接近的是wraps
参数。不幸的是,这似乎并没有用包裹的模拟代替所有成员,而是仅使用模拟对象的成员变量,仅跟踪对__init__
的调用。
例如在 module_a.py:
# Assuming some library class that acts something like this:
class A:
def __init__(self, filename):
self.filename = filename
def get(self):
# ... Some complicated code, involving state and disk access ...
return something
def some_fnc(filename):
a = A(filename)
a.get()
a.get()
a.get()
a.get()
在 test_module_a.py:
import unittest
import unittest.mock
import module_a
class MockA:
def __init__(self, *args, **kwargs):
self.i = 0
pass
def get(self):
# Fake version that returns dummy values,
# but more complicated than simply returning some value.
# Easy to reason about. If this gets complicated then you have problems.
print(self.i, 'is gotten')
if self.i > 3:
return 5
self.i += 1
return 1
class SomeFncTestCase(unittest.TestCase):
@unittest.mock.patch('module_a.A', wraps=MockA)
def test_it(self, m):
module_a.some_fnc('in_file')
m.assert_called_with('in_file')
m.get.assert_called()
MockA.get被调用,第一个断言通过,但是第二个断言失败。
我缺少一些功能吗?可以做我想做的吗?我的建议有什么特别糟糕的理由吗?
答案 0 :(得分:0)
您可以使用patch
版的Mock对象,通过在被调用方尝试实例化module_a.A
时将其设置为返回值,来返回包装模拟类的MagicMock实例。
class SomeFncTestCase(unittest.TestCase):
@unittest.mock.patch('module_a.A')
def test_it(self, m):
mock_a = MagicMock(wraps=MockA())
m.return_value = mock_a
module_a.some_fnc('in_file')
m.assert_called_with('in_file')
mock_a.get.assert_called()
本质上模拟m
的Mock A.__call__
和mock_a
类的模拟实例A
之间存在区别。包装MockA
的实例)。