Understanding Unittest.Mock

Patching Objects and Dicts

Your browser needs to be JavaScript capable to view this video

Try reloading this page, or reviewing your browser settings

This segment explains how can we use patch on dictionaries and existing objects.

Keywords

  • Python
  • test
  • function
  • replace
  • mock
  • internal
  • dependencies
  • dict
  • open
  • object

About this video

Author(s)
Mario Corchero
First online
25 December 2018
DOI
https://doi.org/10.1007/978-1-4842-4413-5_9
Online ISBN
978-1-4842-4413-5
Publisher
Apress
Copyright information
© Mario Corchero 2019

Video Transcript

In this segment, we’re going to see how can we… how can we do patch.object for patching objects, patch.dict for patching dicts, and how it can be really useful for testing when our source code depends on environment variables. Let’s see how can we use patch, uh, within all the targets. These are basically little things that we can find within unittest.mock.patch function. So let’s say for example here with duck, right, we have a duck class and this has, uh, walk method self, uh, which is print, um, spectator, uh, Look, a flying duck. And then we have, uh, method fly which, uh, basically it does the same thing. Well, sorry, walking like and flying duck. Okay. So we have this class, right. And, uh, let’s assume we have two ducks. Goes duck. And the second duck. Okay. Now let’s say that we want to patch the first duck, so, you know, whenever it flies, we control what we do, but we don’t want to change the second duck. So a great way to do it is with patch.object. So we can do from unittest.mock import patch, okay, as we used to do. And, uh, and now what we can do is, uh, we can patch one of them. So we do with patch.object on the first duck. So here we pass the actual, um, the actual object, okay. So we are… you can see that we are not passing in between codes, but they are object and then we can… we say the action that we want to patch which is fly. And now, uh, it’s just going to be a mock. And then whenever, we now, um, do anything whenever we, like, just call the methods, want to see what happens, right. Then actually instead of printing, let’s do return here. This will be clearer. Because then what we can do is we can do here in duck1.walk. Okay. So this is the second one. I’m just going to think it’s going to do is fly. Okay. So what’s going to happen here. Oh, sorry, we have to run this again then we want to print this. Right. If I had them here. Okay. Okay. So here we can see that… again, we run this. No. I think we need to recreate it and we run it. So here we can see that, you know, duck1.walk is, you know, that’s been changed, which makes sense. But then when we call fly, only on the first duck. We see the change of behavior which is basically that this was… this was changed. We manage to mock it right. We managed to patch it. Now this is… this is really useful for scenarios like this one or where we are trying to just change the behavior of one of the methods or one of the object because T is patch on the class for example of where to use… just patch on the original file duck and then fly, we changed everything. Uh, but with patch.object, we aren’t sure that we are only patching… we are only changing the subject. Sometimes as this time or as in this scenario quite likely what do you want to happen is… and this is a place to patch. You just want to change specific method so you can do mock.return_value = “Spectator: Look, a flying pig” alright. And here you can see that. We changed it. Now if that’s all we want to do, we can just… we can just… when we patch whether its subject or just normal patch, we can tell… we can tell patch with the… what to change things for. So here we can patch for Example with a lambda and then just return that, right. If we do this, what’s basically happening is we are doing patch.object or patch where it’s in patch to just go to duck then find a fly to it then they change by this. And we get the same result as we can see here which is… but is much shorter. There are a lot of options that you can patch patch.object which are the same as… kind of the same as the patch. One of them as well is, you know, you might want to have a new method, just fly2 and this will fail. But what you can do is you can say new equals… nah, uh, or create, I think, um, that’ll create the object. That’ll create the method for you. So now duck has new one which is fly2. Alright. So, you know, patch.object allow us to patch a specific object and… because it has the same, uh, interface as patch, it also has a lot of attributes that we are not diving into that allow us to make it in a simpler way on create new object or create new names because if we try to patch something that doesn’t say that we’ll fail, and this is just the nicer way to work with, uh, the patch method. So in situations, we also want to patch, uh, maybe a dictionary. Let’s say we have data dictionary, which basically had two keys, key1 and key2 with value2. Now we want to change this dictionary into some… like an scope like as we were doing with patch. How we can do… we can do this with, uh, from unittest.mock import patch. Our swiss army knife and, uh, then, you know, let’s see and how everything is working here. Now we do with patch.dict and here we need to pass the original dictionary and then the value is going to change, okay. This is something that might confuse other people. So it’s just the value we want to change. So here we say, um, uh, we want to make, um, key2 to be, uh, patched_value2 and we want to add 1, a new one which is key3, okay, it’s value 3. Okay. So now with this, if we print data here, uh, we print it afterwards, we can see that, uh, when we are within the… within the, um, context manager the second key… the value of the second key has changed to what we told him to change. Um, it’s being… we found the new value, a new item to the dictionary. Something else to be aware of is that you can change things here. So we can say for example, data[“key4”] and then patched_value4. And that will be added only within, uh, within that context manager. This is because what’s happening is it’s basically, when it gets into the… into the, um, to the context… like within the scope, like when it calls out on enter is it’s going to apply this change initially. And when it exits, it’s just going to… it’s just going to put the dictionary as it was before calling enter which it saves the original one. This is… you know, this might look not that powerful, but it is actually really, really interesting because something we can do here is, um, like, first let’s say we have function import os get_unix_user() : and now we do print(os.getenv(“user”)). This is, uh, this is… this is a function that’s just going to print the user name that we’re running, uh, in the unix, right. So let’s say we do get_unix_user() and this is just going to print, you know, my username. You know, if we wanted to patch like the environment variables, um, one good thing that we could do is we could patch os.getenv that a match is here, wait because we saw her patchworks and that’s not an issue in this case because we are patching the real dictionary that’s just a name when we use patch.dict. We could just patch that dictionary of environment variables which is, it’s really nice to see how it works, because we would just changing the values that we want in the dictionary. So if we do patch.dict os.environ, and then we say like hey, I just want the user within this scope to be root, right. And now we print this again. We can just change it there. This is really, really handy when you’re writing test that depend on environment variables. You can just, you know, change whatever environment variable you want just for the… just within the scope of the test which is really, really happy.