简体   繁体   English

Python unittest 补丁模拟实体类

[英]Python unittest patch mock entier class

I have a class that I want to patch in my unittests.我有一个要在我的单元测试中修补的类。

class OriginalClass():
   def method_a():
     # do something
   
   def method_b():
     # do another thing

Now I created another class to patch it with, so the code for patching it is like现在我创建了另一个类来修补它,所以修补它的代码就像

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()    

This works exactly as I want it to and I can return whatever responses required for my unittests.这完全符合我的要求,我可以返回单元测试所需的任何响应。

Now this issue is when I want to verify that a method is called with the right parameters in the unittests.现在这个问题是当我想验证是否在单元测试中使用正确的参数调用了一个方法。 I tried我试过

mock_instance.method_a.assert_called_once()

But it fail with error AttributeError: 'function' object has no attribute 'assert_called_once' .但它失败并出现错误AttributeError: 'function' object has no attribute 'assert_called_once'

How can I test the method calls here?我如何在这里测试方法调用?

AttributeError: 'function' object has no attribute 'assert_called_once'. AttributeError: 'function' 对象没有属性 'assert_Called_once'。

Once mock object is created, there is no method_a exists, you have to call once m.method_a() before assert.一旦创建了模拟对象,就没有method_a存在,您必须在断言之前调用一次m.method_a()

    m = mock.create_autospec(OriginalClass)
    m.method_a()
    m.method_a.assert_called_once()

patch mock entire class补丁模拟整个班级

I took it as mock the whole class and all its methods, I would take an example from herehttps://docs.python.org/3.3/library/unittest.mock-examples.html我把它当作整个班级及其所有方法的模拟,我将从这里拿一个例子https://docs.python.org/3.3/library/unittest.mock-examples.html

Applying the same patch to every test method, Here is my example, patch the entire Primary class as MockPrimay for every methods and every tests, setup or SetupClass could be added for the methods needed, even the whole class is mocked, but not every methods to be used in the tests.对每个测试方法应用相同的补丁,这是我的示例,为每个方法将整个 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)

The Primary is needed for the Secondary for this test次要考试需要主要考试

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

I think wraps can be useful here:我认为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()

Output:输出:

<MagicMock name='Person.name' id='139815250247536'>
5
...
raise AssertionError(msg)
AssertionError: Expected 'age' to not have been called. Called 1 times.
Calls: [call()].

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM