Patch - Why won't the relative patch target name work? Patch - Why won't the relative patch target name work? python python

Patch - Why won't the relative patch target name work?


The patch decorator requires the target to be a full dotted path, as stated in the documentation:

target should be a string in the form ‘package.module.ClassName’. The target is imported and the specified object replaced with the new object, so the target must be importable from the environment you are calling patch from. The target is imported when the decorated function is executed, not at decoration time.

"Channel" is just a string, and patch does not have enough information to find the proper class. This is not the same as the name Channel you use elsewhere, which is imported at the top of the module.

The second test fails because Channel gets imported in the test module then patch replaces Channel in notification.models with a mock object. What patch actually does is change the object the name Channel used inside notification.models point to. The name Channel in the test module has already been defined, so it is not affected. This is actually better explained here: http://www.voidspace.org.uk/python/mock/patch.html#id1

To access the patched version of your object, you can either access the module directly:

import unittest from mock import patch from notification.models import Channel, addChannelWithName  from notification import models class TestChannel1(unittest.TestCase):     @patch("notification.models.Channel")     def testAddChannelWithNamePutsChannel(self, *args):         addChannelWithName("channel1")         models.Channel.put.assert_called_with("channel1") 

Or use the patched version passed as an extra argument to the decorated function:

class TestChannel2(unittest.TestCase):     @patch("notification.models.Channel")     def testAddChannelWithNamePutsChannel(self, mock_channel):         addChannelWithName("channel1")         mock_channel.put.assert_called_with("channel1") 

If you just want to quickly patch a single method on an object, it's usually easier to use the patch.object decorator:

class TestChannel3(unittest.TestCase):    @patch.object(Channel, 'put')        def testAddChannelWithNamePutsChannel(self, *arg):         addChannelWithName("channel1")         Channel.put.assert_called_with("channel1")