简体   繁体   中英

mocking injected class method

I have a Gateway class that has contains an instance of a Resource class. I've already done my unit testing on Resource, and to simplify testing, Resource is injected into Gateway as a dependency at initialization:

class Gateway:

  def __init__(self, resource):
    self._resource = resource(Master)

  def list_things(self):
    return self._resource.list_resource()

Now I'd like write unit test for Gateway to verify that resource.list_resource() gets called as a result of calling gateway.list_things() . My best attempt doesn't work:

class TestGateway(unittest.TestCase):

    def test_list_things(self):
        mock_resource = Mock()
        g = modbus.gateway.Gateway(mock_resource)
        g.list_things()
        mock_resource.list_resource.assert_called_once()

The result:

AssertionError: Expected 'list_resource' to have been called once. Called 0 times.

What am I missing?

In the actual use case of the mock_resource that you passed into Gateway for your test case, the constructor in Gateway actually makes a further call to the resource argument as a constructor, so that what the test expects is actually emulating the checking of the call against the class method, not the instance method of the mock_resource . Demonstrating this using just the minimum number of statements can be done using the following:

>>> mock_resource = Mock()
>>> self_resource = mock_resource('Master')  # emulate Gateway.__init__
>>> self_resource.list_resource()            # emulate Gateway.list_things
<Mock name='mock().list_resource()' id='140441464498496'>
>>> mock_resource.list_resource.assert_called_once()  # test_list_things
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/unittest/mock.py", line 795, in assert_called_once
    raise AssertionError(msg)
AssertionError: Expected 'list_resource' to have been called once. Called 0 times.
>>> self_resource.list_resource.assert_called_once()  # test the _actual_ call
>>> 

Note that I had assigned self_resource to emulate the self._resource = resource(Master) statement in the constructor for Resource , and the mismatching of the test vs. what is actually executed should now be apparent.

To fix this, the test should check the call like so:

    def test_list_things(self):
        mock_resource = Mock()
        g = modbus.gateway.Gateway(mock_resource)
        g.list_things()
        # mock_resource.list_resource.assert_called_once()
        g._resource.list_resource.assert_called_once()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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