Python单元测试补丁模拟整个类



我有一个要在单元测试中修补的类。

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

最新更新