Skip to content Skip to sidebar Skip to footer

Patch - Why Won't The Relative Patch Target Name Work?

I've imported a class from a module, but when I try to patch the class name without it's module as a prefix I get a type error: TypeError: Need a valid target to patch. You supplie

Solution 1:

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: https://docs.python.org/3/library/unittest.mock.html#where-to-patch

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

import unittest 
from unittest.mock import patch 
from notification.models import Channel, addChannelWithName  
from notification import models 
                 
classTestChannel1(unittest.TestCase): 
    @patch("notification.models.Channel") deftestAddChannelWithNamePutsChannel(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:

classTestChannel2(unittest.TestCase): 
    @patch("notification.models.Channel") deftestAddChannelWithNamePutsChannel(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:

classTestChannel3(unittest.TestCase):
    @patch.object(Channel, 'put')    deftestAddChannelWithNamePutsChannel(self, *arg): 
        addChannelWithName("channel1") 
        Channel.put.assert_called_with("channel1") 

Post a Comment for "Patch - Why Won't The Relative Patch Target Name Work?"