我有一个要在单元测试中修补的类。
class OriginalClass():
def method_a():
# do something
def method_b():
# do another thing
现在我创建了另一个类来修补它,所以修补它的代码就像
class MockClass(OriginalClass):
def method_a():
# This will override the original method and return custom response for testing.
patcher = patch('OriginalClass', new=MockClass)
mock_instance = patcher.start()
这正是我想要的,我可以返回单元测试所需的任何响应。
现在,当我想验证在单元测试中使用正确的参数调用方法时,就会出现这个问题。我试过
mock_instance.method_a.assert_called_once()
但它失败了,出现错误AttributeError: 'function' object has no attribute 'assert_called_once'
。
如何在此处测试方法调用?
我认为wraps
在这里很有用:
from unittest.mock import patch
class Person:
name = "Bob"
def age(self):
return 35
class Double(Person):
def age(self):
return 5
with patch('__main__.Person', wraps=Double()) as mock:
print(mock.name) # mocks data
print(mock.age()) # runs real methods, but still spies their calls
mock.age.assert_not_called()
输出:
<MagicMock name='Person.name' id='139815250247536'>
5
...
raise AssertionError(msg)
AssertionError: Expected 'age' to not have been called. Called 1 times.
Calls: [call()].
AttributeError:"function"对象没有属性"assert_colled_once"。
一旦创建了mock对象,就不存在method_a
,您必须在断言之前调用一次m.method_a()
。
m = mock.create_autospec(OriginalClass)
m.method_a()
m.method_a.assert_called_once()
补丁模拟整个类
我把它作为整个类及其所有方法的mock,我将从这里举一个例子https://docs.python.org/3.3/library/unittest.mock-examples.html
将相同的补丁应用于每个测试方法,这里是我的例子,为每个方法和每个测试将整个Primary类补丁为MockPrimay,可以为所需的方法添加setup or SetupClass
,甚至可以模拟整个类,但不是测试中使用的每个方法。
from tests.lib.primary_secondary import Secondary
@mock.patch('tests.lib.primary_secondary.Primary')
class TestSecondaryMockPrimary(unittest.TestCase):
def test_method_d(self, MockPrimary):
MockPrimary().process()
MockPrimary().process.return_value = 1
oc = Secondary()
self.assertEqual(oc.method_d(), 1)
import tests
self.assertIs(tests.lib.primary_secondary.Primary, MockPrimary)
此测试需要初级
class Primary(object):
def __init__(self, param):
self._param = param
def process(self):
if self._param == 1:
self._do_intermediate_process()
self._do_process()
class Secondary(object):
def __init__(self):
self.scl = Primary(1)
def method_d(self):
return self.scl.process