I'm writing a new method inside a child class. The method publishes a json object onto an MQTT broker and times the response from the client. In order to unit test it, I would like to patch the methods (called by the method under test) that publish the json message and time the response. Without the ability to mock, there is a dependency on an MQTT broker existing and a client to publish a response. Another reason is to introspect the arguments (the json object) passed into the mock method by the method under test. So far, I have been able to patch the class' init method as this initialises many things that I don't need in order to test my method (loggers, config files etc). However, when I try and patch out another method on the same class. The method under test calls the real publish method, and not the mock. I'm working in python 2.7 (not by choice). I'm using behave as the unit test framework.

I have a feature to unit test, which relies on a similar context for each scenario to run. Therefore, in the environment.py (similar to pytest's confest.py), i'm instantiating the class once, to be run through the entire feature. This works fine. When I add another patch to the 'publish_json' method. It calls the real method and falls over because there isn't an MQTT broker running.

I've also tried mocking the 'publish_json' method using MagicMock, within the test step implementation file. However, this returned a call() object containing no arguments.

The structure of the classes.

BaseClass
    __init__ which i've successfully patched.
    contains the publish_json which i'm unable to patch.

    aSubClass(BaseClass)
        containing derived functionality 

        anotherSubClass(aSubClass)
            containing the new method to test.
            will eventually use the functionality within the parent classes.
# environment.py...
from anotherSubClass import anotherSubClass

def fake_pub():
        print("the fake json publisher has been called!!!")
        return True

@fixture
def anotherSubClass_mocked(context):
        # pacthing out the base class initialisation
        # patching the publish_json method which isn't working
        with patch.object(anotherSubClass, "__init__", lambda x,y,z: None), patch.object(anotherSubClass, "publish_json", fake_pub):
                context.tester = anotherSubClass(None,None)

# steps.py
@when(u'the tester sends a START message')
def step_impl(context):
    # patch the publish_json call here and validate the json contents (call_args)
    context.tester.publish_json = Mock()
    context.tester.time_mqtt_msg("START")
    args = context.tester.publish_json.call_args()

# method under test
from aSubClass import aSubClass


class anotherSubClass(aSubClass):

    def time_cloud_msg(self, msg, timeout=10):
      mqtt_msg = {"msg":"TEST", "time": self.generate_timestamp()}
      print("Sending message to remote broker")
      self.publish_json("remote", "command", mqtt_msg)
      # timer not yet implemented... :-(

Expecting the fake json publisher to be called. In the first instance (in environment) the actual publish method was called In the second instance (in steps) the mock was supposedly called with nothing (call())

0 Answers