Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set your subtitle preferences in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please refer to our video player troubleshooting guide for assistance.

patch.object() as Context Manager

00:00 Now, what if you don’t want to mock an entire module, but you only want to mock a particular object within that module? Well, fortunately, we have a function called patch.object() to do exactly that.

00:15 patch.object() can be used as a context manager or a decorator just as patch() can. Let me show you what that looks like. So it’s basically the same thing here, except that this argument is no longer the path to the object that you want to mock—it needs to be the object itself.

00:35 So when we do patch.object()it’s with patch.object()the first argument is the actual object that we want to patch, not the path to it.

00:48 So this needs to be requests and we want to patch requests.get(), and that is coming from my_calendar.py. So again, just higher level, remember that we’re testing get_holidays(), and get_holidays() uses requests.get().

01:07 We want to patch this .get() method, not the entire requests module. One way we can do that here in our tests.py is say from my_calendar import requests.

01:23 That way, we have this object

01:28 and we can use it as the first argument here to patch.object(). Then the second argument is the object that we want to patch. We’ve brought in this requests module and we want to patch 'get', and this is a string. And then we can set the attributes, the Mock object attributes that we are now familiar with, such as .side_effect.

01:52 We’ll set that to a Timeout.

01:55 So we’ve done patch.object() on the requests module, and specifically the .get() method of that module, and set its .side_effect to Timeout.

02:05 And instead of mocked_requests, let’s call this mocked_get.

02:11 Previously where we had mocked_requests.get.side_effect, we actually don’t have to do that anymore because we’re doing that with patch.object().

02:19 We’ve set the .side_effect of .get() and then with self.assertRaises(Timeout): we just call get_holidays().

02:30 And I’m getting a syntax kind of warning here saying that it’s not used, it’s an Unused variable. We actually don’t need to use it since we’re already, you know, we’re patching it, we’re not using this variable directly.

02:44 So I’m just going to go ahead and change it to an underscore (_), so that removes the warning there. Let’s save that and try to execute our tests,

02:57 and the test succeeds. Let’s just try to break this just to make sure we’re actually doing something that’s working, so I’m just going to change this to 'getz'—just, I don’t think there’s an attribute in the requests module—or an object, rather—called .getdfz.

03:19 So let’s go ahead and see what happens when we run our tests. Okay, so module 'requests' from—this path—does not have the attribute 'getdfz'.

03:29 I just wanted to make sure that what we’re doing is actually working and we are actually patching this particular attribute from requests. Let’s just run that test again, and it succeeds.

Glen Jarvis on April 25, 2022

With a context manager, the referencing variable can be omitted if not needed. (That is, there’s no need for the as _ syntax if the variable is not needed.

For example, this is cleaner:

class TestCalendar(unittest.TestCase):
    def test_get_hoildays_timeout(self):
        with patch.object(requests, 'get', side_effect=Timeout):
            with self.assertRaises(Timeout):
                get_holidays()

instead of this:

        with patch.object(requests, 'get', side_effect=Timeout) as _:

Become a Member to join the conversation.