Intro to Mocking: Why Unit Testing Doesn't Have To Be So Hard by Daniel Davis

This video features Daniel Davis at DjangoCon US 2015 in Austin, Texas, USA.

Intro to Mocking: Why Unit Testing Doesn't Have To Be So Hard by Daniel Davis
0:38:34
Published November 3, 2017
1,342 views

Intro to Mocking: Why Unit Testing Doesn't Have To Be So Hard by Daniel Davis

Many developers want to write better code, but simply don't know how to write units tests for:

Code that calls other code (i.e. code with dependencies)
Methods that have no return value
Code that throws exceptions
Mocking provides a valuable tool for solving these problems. In this talk, we'll discuss the scenarios in which Mocking is useful, the strategies for addressing each of the cases above and write simple, clean unit tests using the built-in Mock library.

Help us caption & translate this video!

http://amara.org/v/HH6d/

Summary

Mocking makes unit tests more reliable by replacing uncertain or costly dependencies with controlled test doubles. Daniel Davis explains how Python’s `unittest.mock` can patch functions and methods, set fixed return values, provide sequences with `side_effect`, verify calls and arguments, and raise exceptions on demand. These techniques help test code that depends on randomness, has behavior rather than return values, calls external services, or needs difficult error conditions; for Django code, he recommends choosing pragmatically between mocks and Django’s own test tools when testing framework integration or complex database relationships.

Key takeaways

  • Patch dependencies at the location where the code under test looks them up, then set a deterministic return value.
  • Use `side_effect` to return successive values across calls or to raise a specific exception.
  • Use mock call counts, `assert_called_once_with`, and `call_args_list` to verify behavior and arguments.
  • Mocks can make tests faster and clearer by avoiding databases, network APIs, and hard-to-reproduce failures.
  • Mocks are not always the right tool: use Django’s test runner, client, fixtures, or integration tests when framework behavior and complex relationships are what need testing.
  • Python 3 includes `unittest.mock`; Python 2 projects can install the mock package.

Summarised automatically from the transcript.

Transcript

7,897 words · auto-generated Show

Automatically transcribed, so expect mistakes in names and technical terms.

0:16

Speaker 1: Alright, uh this is Intro to Mocking, while unit testing doesn't have to be so hard. I am Daniel Davis. A little bit about me. I've been a software developer for about eight years now. Uh I am a senior consultant at Excela Consulting in Washington, D. C. And a fun fact about myself, I uh recently, well not recently, in December I ran the gingerbread the Jingle All the Way 5K. dressed as a giant gingerbread man. If you want to see what that looks like, this is a candid picture of that. It was awesome. I have some recommendations on things you should not wear when running a race. Felt is one of them. So All right. Uh let's do a quick survey. Who here in the room has ever been frustrated by an experience writing a unit test? Show of hands. Yeah. Everybody in this room here, uh myself included. Uh thank you all for raising your hands.

1:02

Speaker 1: Um I think I came to this with the same sort of problem you guys have had. I sort of struggled to write unit tests for so many years. It was very, very frustrating and hard until I finally learned about mocking. and sort of that made the lights, you know, the light bulb go off in my head. Everything sort of clicks. I think I have a rendering of that. That was sort of how it felt for me. But my my point is this. I think a lot of us here in the room are in the same boat. Um we all kind of want to write better unit tests and what you know I've I've talked with a lot of people here and they just say I really wish somebody would sit down and write a presentation on this stuff and like just tell me what I need to know. So I wrote this with that in mind. And if that happens to be you in your particular situation Hopefully this helps you. Um so let's talk about unit tests.

1:48

Speaker 1: All right. Uh hopefully you've seen this at some point in time. If not, this is Martin Fowler's pyramid of testing. The idea is that he tries to quantify how much of our testing should be unit tests versus integration tests versus like UI or manual testing, that sort of thing Obviously the significant majority of it is unit testing, which is kind of ironic because many of us are really bad at unit testing and we don't write lots of unit tests like we should. When I ask people about this stuff, I get all kinds of stories about why they shouldn't. For example, they tell me like, well, you know, it's really good when the problems are easy, but I run this problem when, you know, I find these other things I have to test, and then I have to write tests for my tests. and the code gets really complicated. I call this the rabbit hole of testing. It's kind of like going down different layers and it becomes really, really hard. And so

2:33

Speaker 1: you know, mocking can help us with that. No no worries. Another thing I hear is that uh people tell me I I spend too much time writing these tests. Right? I write lots and lots of code, and then I have to write more tests for my code, and then I have to write tests for my tests, and it's just it's a big problem. Mocking can help us solve that. Lastly, I hear people tell me that uh we can't really write tests for some things. Just there's just so much stuff you can't unit test. This is sort of a half-truth, right? I admit that there are things that we cannot cover just simply by using unit tests. But I think we way overestimate what that portion is. It's actually a very, very well-known and small fraction of things that we cannot test. Unitesting is an incredibly powerful tool. Mocking helps us make that more valuable and more, it helps us fill that space. So, mocking makes unit testing easier.

3:21

Speaker 1: So what are mocks exactly? What what is that? Mocks form this sort of uh strange uh subclass of a thing called a test double in testing The idea is we typically have like test stubs or test spies or mock objects, that sort of thing. You'll hear me sort of use these, I'll call these things mocks. interchangeably, but understand that maybe in an academic setting this might be a more important distinction. For the purposes of this presentation though, I'm just going to call it a mock. So what are those things specifically? Well you have a test stub and the idea is that it provides a canned response to a method call. If you have a spy, which is a real object that behaves like a real object until uh a certain condition is met, then it does something else And you have a mock, which helps us to verify that something was called or you know verify a behavior, right?

4:06

Speaker 1: So here's the thing. Does anybody in the room feel like after I've given that explanation that they understand mocking significantly better and they're ready to go test? No, of course not. Like for me, I think what helps when we talk about mocking is understanding the types of problems that mocking helps us to solve. Okay? So let's talk about the things that mocks help us solve. First problem. What happens if you have a dependency, right? So here I have this sample method foo, everyone's favorite. And depending upon the value you get back from method bar is going to impact how the method foo behaves. So this is a dependency. We could write this down as foo of x, you know, is going to depend on bar, right? The problem is that in order to understand how foo

4:52

Speaker 1: works, I need to also understand how bar works, and that creates a big problem If I could eliminate that dependency, if I could uh figure out a way of making uh gaining certainty with bar, then I could you know test that more effectively. So mocking helps us with this. Second problem. What if I have a method that has no return value? So I have this method here, foo, and depending upon the value of x, it's either going to call bar or it's going to call something else. But how do I know if bar is called? Now sure we could write a unit test for this. And that unit test could say, well, depending upon the side effects that bar has, you know, we could sort of introspect it or figure it out somehow, right? But this is a really bad way to write tests. It's really, really cumbersome and painful. Right? If I had somewhere just saying, did bar get called, I would have much greater certainty and know better.

5:37

Speaker 1: So mocking helps us with that. Lastly. If I have a situation where I want to generate uh an error or an exception, right? But that exception is really hard to generate. So not talking about like a type error or uh uh file not found. Right? So in this case, maybe something that that uh would be very difficult to generate, like a memory error. If I could technically generate this somehow, like by adding load to the server or whatnot, but that's just it's not a good way to test. It's very hard. If I could just reliably call that, make testing a lot easier. So that's what mocking helps us solve. A couple other things. Let's say you're happening to use a popular web framework that insists that you have you know database calls for all of your methods and spins up a test database like Django does. If you didn't have to have that test database, your tests would be a lot faster. In some cases, mocking a model makes a lot of sense.

6:24

Speaker 1: So this can be very helpful there. It also helps us to reduce complexity. So if I'm writing simple tests, it's really easy to understand what those tests do. And it's really easy to write them because it's quick and simple. So mocking helps with that. One other thing I want to point out is that uh we don't think about this, but if you have people who are working with you, you're collaborating, and somebody hasn't written their method yet. If you can mock those methods that haven't been written yet, you can write unit tests for them. This is way better than if you had to wait for all of those things to be done. You could just, you know, you'd have to wait for all the components to be finished before you could start testing. it. So this makes you more productive and efficient. You can test things earlier and that's better. So great, you're sold. You want to use mocking. So how do I actually do this? Um fortunately for us in Python

7:11

Speaker 1: we have lots of options. Um the one we're gonna focus on here is the mock or the magic mock library. Uh it's very popular, it's extremely powerful, and Good news for everybody, if you're using Python 3, it's included in as part of the standard library. So that's awesome. Uh there are some other options I want to toss out there in fairness. So if you uh are familiar with Ruby's Flex mock, There's uh FlexMock. If you've ever used EasyMock in Java, there's Mocks, uh, Mocker, there's Dingus, which has an incredible name for a framework. Um Fudge, if you've ever used Maquito, uh coming from like the Java space, or if you're a big fan of doc tests, there is minimock. Okay But for the purposes of this, I'm going to focus on doing this with mock. Just know that any of the examples I do here, we could be

7:57

Speaker 1: we could probably do those in those other frameworks as well. Alright, so let's do a sample problem. Like let's let's actually put this into code and do something with it. Um it really helps to think about those types of problems, so let's create a little problem space for ourselves, a real-world situation. Let's say we wanted to build a Tinder competitor, okay? That's a great example app, right? Tinder is the popular dating app where you get a random picture of somebody and you either swipe to the right or to the left to indicate your preference Um but we want something to appear to the software development community, of course, right? So like you've got Tinders already taken, you've got Grinder. Let's let's think of maybe, I don't know, like let's call it Docker, okay? So the uh the Docker dating app is what we're gonna use, because I think this is a great idea.

8:44

Speaker 1: Um so So let's say you're building your Docker dating app and we're gonna create a method for this, right? Where we get to a r a random user. The idea is that I want to be able to grab a random user from the database and show that to them. Show that to the current user. The only criteria here is that I can't see the same person and it can't be somebody that I've already swiped on. Okay, so very simple. We could write a simple uh implementation for that. So something like this. So uh get next person is going to uh call the method get random person and then we just go through a loop and says if If we've already seen that person, just keep grabbing random people until you get uh somebody you haven't seen, then return that person.

9:29

Speaker 1: Fair enough? Okay, now those of you who are astute pythonistas will probably notice something interesting about this. There's a bug in this code that of course we found when testing. Which is of course, surely no one could have have seen everyone in the database, right? So if you if you've seen everyone in the database, then you it gets into an infinite loop. We're going to ignore that for now because it makes the problem more complicated and like makes the example less pretty. So let's assume that our database is sufficiently large to do that. So let's represent the relationship here. So get next person is going to call get random person. So we could write a unit test for this, right? Very simple, very easy. So here's my unit test. And it has a general setup, right? We have an arrange method, our preconditions. We just say it's a dictionary of people that I've seen, it's empty.

10:15

Speaker 1: And then expected person that I want is Katie. Uh my action is gonna be to call get next person, I store the result of that, and then I just compare the expected result to the actual result. Very simple and good news. This totally works. It works. It's great. That's so simple, right? Except it also doesn't work. And sometimes it fails. And that's not cool, because like 60% of the time works every time So what's going on here? Like this is a problem. So what happens is that get random person obviously picks a random person out. So that means that there's no way for us to really have any certainty to it. Even if I knew the implementation of get random person, I could not write a unit test for this without mocking. But what if there was some way we could fix the value of get random person?

11:00

Speaker 1: What if we could make that certain? So how do we do that? Easy. We're gonna mock all the dependencies. Yes, that's what we're gonna do. Here's how we do that. Um There is a very simple method here. There's a very simple decorator here called patch. And the idea is that inside of patch, we are going to pass in It's basically the uh module. attribute. So in this case my module is application, and then the unbound method is get random person. Right? When I put that decorator on there, it's gonna pass an argument into uh my test method called mock getrandomperson. Uh and then all I'm really gonna do here is call this thing called uh return value on it. I'm gonna set the value of that to be a fixed value, in this case Katie.

11:46

Speaker 1: So what this does is that whenever that random person method gets called, it's actually going to call the mock method instead, and it's going to return back that fixed value. And that's it. Then we have certainty in our method. Now we know how to get that value back. And good news, it works every single time. Every single time it works. You can call it over and over again, even though that's a random method. We fix the value of it. We can test it reliably. So that's great. So let's take a little bit further. Let's do some variations on this, right? We we rarely work with unbound methods. What about a class? You know, so I have a class. Again, I just restructured this so that that method is inside of a class called application. How demock that? Same idea here. We're gonna have this thing. It's now gonna be patch. object. instead of just patch, and you pass it in the class name and then the method that you want to mock.

12:32

Speaker 1: Everything else about this is exactly the same as the previous example. So it's very easy if you're using, you know, a class or if you're not using a class. Um but what if you're like I'm really kind of new to Python and I'm scared by decorators? I don't really like decorators, they're kind of magical and weird. So yeah, we don't have to have a decorator. We can get rid of that. So here's another example. All we're doing here is we're just going to make a direct assignment. This is awesome because Python allows this. So you can literally just overwrite that method. with uh call to a new object. You could basically setting that method to be a mock, and then we just set the return value. So that's kind of the idea here. this. But what if you're like, okay, you know, I'm actually a bigger fan of context managers. I really love context managers. Well good news. Context managers too.

13:18

Speaker 1: You can use your width statement. That's that's great. All right, so that's the general idea behind sort of mocking uh for a dependency. But what happens if I want to call this thing multiple times? So here's our here's our sample code, but what if I want to test the while loop inside of this? So the while loop, I'm gonna get back, you know, uh a new person each time. So I write a unit test for it. But the problem is is that when I set that return value, I don't really know who I should set the return value to. It's actually going to enter into an in into an infinite loop if I do this. where it's going to be you know over and over and over again because it's going to keep returning the same value. And if that same value is in the list of people I've seen, just keeps going. So how do we fix that? So there's a a method called side effect, and the idea here is we just make a slight change to our method, uh, call this thing here called side effect, and it will take in uh an iterable

14:11

Speaker 1: or a list. So if I pass in a list of the return values that I want, each time that method gets called, it will just return back, you know, the next the next thing in the list. So first it will return back Mary, then Sarah, then Katie. So if I'm testing that and that method gets called multiple times, turns back those values. Okay? So that's really all there is to like dependency, uh dependency management here. It's really not particularly complex, but let's recap. So we can use mocking and patching to sort of bring certainty to all of our dependent methods. Um we can eliminate those dependencies in the code, even if that even if those dependencies are unfinished. Notice that I didn't point out how uh get random person was was implemented. It didn't matter. That code could not even work

14:58

Speaker 1: But I was able to still uh you write unit tests for this. Um, lots of different ways to do it. Pick your favorite. Uh show of hands in the room. Who likes doing it without the decorators? Anyone? See a couple of hands. Yeah, a token group of folks. I find there are always like a handful of people who are like, this makes more sense to me. This is better. And it's it's great. There's in some cases it makes more sense to do it uh in that style, in some cases it makes sense to use the decorator. Um it's up to your personal preference. All right, second thing mocks help us with. Mock needs to verify behavior. Okay? So let's uh set up a problem space for us. Uh again, let's keep on with our with our Docker dating app, but let's talk about the matching system here. So when a user swipes to the right, uh

15:44

Speaker 1: if the other user has indicated that they like them, then what we want to do is we wanna send both of them uh a message. You know, send both of them a message saying you're a match. Okay? If the other user has indicated they dislike them, then we want to sort of let them down gently. Let them know there's there's other fish in the sea, there's other you know opportunities And if they haven't evaluated you yet, then what we want to do is send the give that time message. So that's just kind of the general setup here for how we react to someone uh doing the action of swiping. So a simple implementation for this. Very easy. We could just, you know, have an evaluate method, takes in two people. Uh if person one is in person two is likes, then we send both people an email. If person one is in person two 's dislikes, then we call the let down gently method. And if person

16:29

Speaker 1: one is not in your likes or your dislikes, then we're going to call the give it time method. Simple enough, but there's sort of a problem with this. How do I test this? It has no return values. How do I know that this is functioning properly? We all agree that this has logic in it and it needs to be tested. But how would I do that? So let's focus in on the middle section here and let's try and write a unit test for it. We can do behavior verification. with mocking and it's very simple. It's very, it's basically the exact same. We're just gonna tweak it slightly. We have that patch decorator, so again application dot letdown gently. It's gonna give us a mock of the letdown gently method. Uh in my arrangement here I just have person one is named Bill and person two is just a dictionary of you know the people they like and

17:15

Speaker 1: uh that the other person has liked or disliked. I call my action to evaluate it. The only thing that's different here is in my assertion, I'm gonna call this method called call count. What's cool with mocks is that they actually will record every time that they've been called and it will allow you to verify and say how many times were you called? And you can use that to verify the behavior. So if it was called one time, we know it's functioning correctly. It should have been called given the situation I've I've created here. So that's nice, but you might say, well, a more robust way of doing this would be like, what about checking the parameters instead of just how many times it was called? Right? That makes sense. So we can do that too. Same exact setup here. Only difference is we're gonna call this method called assert called once with. Which is quite a mouthful to say, but uh all it's doing is it's checking two things.

18:04

Speaker 1: It was called one time, and it's checking that it was called uh with the appropriate parameters, in this case person one. So this will allow us to verify that that method was called with exactly what we expected. Now one variation of this is you might say, well, that's nice, but shouldn't we also check the other methods to make sure that they're not being called? So for though for example those things, right? Um we might have a bug in our code somewhere that says you know uh maybe we're we're uh uh calling everything or whatnot. So how could we check against that? So that's great, that's a good idea. Only problem is we're gonna run into having to mock multiple things, right? So can we even do that? Well of course. In Python, we have the ability to stack decorators. So if you need to patch multiple methods, you can do that.

18:50

Speaker 1: Just stack them one on top of the other, and it works great. One thing I do want to point out about this though is that if you uh stack the decorators, because of how Python evaluates those, you have to be very careful about how the order in which your arguments come in. So for example, the the mock give it time is the first uh the first parameter as opposed to the third, because Python evaluates them from the bottom up as opposed to top down. So people find this, can find this kind of counterintuitive, but just something to keep in mind so you don't uh end up getting those mixed up and calling the wrong mock. Everything else with this is pretty much the same. We basically have uh we basically just gonna look at the call count and make sure that it's set at zero for those other methods and

19:35

Speaker 1: And verifier arguments with the one we meant to call. So if you're concerned about possibly mixing up the ordering on those those decorators. You can try using patch tab multiple, which gives a little bit more of a rigor and structure to it. Uh it'll make it a little easier to kind of uh fill those out and and then it comes in the order that you sort of expect. So it was just another variation of how you can do this, just another thing you can try if that's uh if that makes sense to you, if that's what you'd like to do. Everything else pretty much stays the same. Okay. All right. So what about testing things that have been called multiple times? We talked about verifying the behavior of it being called once. But what happens if we have a case like here at the top where we call send email twice? We can't really evaluate you know the parameter of the parameters getting passed in.

20:21

Speaker 1: Which what which call are we talking about? So let's take a look at how to how to fix that problem. So in this case, we're going to do uh we're going to have a thing called, we're gonna call a method called call args list. And that's gonna basically record every single time that the uh method was called and the parameters that were in there. It returns back a list of call arguments. The idea is then I can assert that against uh it's like a little wrapper. So the call uh call is just a wrapper around the parameters of your uh of your method So we can evaluate that against you know against person one and person two. So if we call it twice, we say the first call, we're looking for person one, second call, I'm looking for person two. Okay?

21:06

Speaker 1: Everyone with me so far? Shaking hands? Okay, cool. All right, almost done. I know this is the end of the day for you guys. If you need to take a brief kitten break, uh I've got a kitten for you. Um If you guys are maybe not cat fans, maybe you're dog people, I have some delightful corgis to make you happy. Um okay. So we talked about three things that mocking helps us to solve, right? Mocking helps us to solve uh mocking helps us to solve dependencies. Mocking helps us to solve to verify behavior, and mocking also helps us to evaluate uh exceptions being thrown. So let's set up a problem, right? Let's say in our awesome Docker dating app that we wanted to have a payment system because of course adding a premium feature totally works every time.

21:53

Speaker 1: It's great. Um I'm in this case I'm just gonna use Stripe because it was convenient and easy. but you can imagine doing any other number of services. So I've created a simple submit payment. method. The idea here is it takes in a stripe token. I've literally just copied and pasted this from their from their tutorial more or less. I have an API key that I set and then I create a sample charge. In this case it's going to be $10 You can imagine this being in like your Django View code or maybe in one of your forums or something of that nature. So even though I'm not necessarily pointing out you know, Django specific stuff. Uh I'm just sort of pulling these things out to keep the simp the examples clean, but this is very easily something that could be in your view code. In the case of this uh the charge going through, we'll just return back the charge.

22:41

Speaker 1: And if it uh ends up failing though, like so let's say the card gets declined. Well then you have uh it'll generate a card error and we want to catch that and maybe in this case we'll uh we'll just you know pull out the body of the error and we'll pass it back to the user. Some some sort of default implementation here. It doesn't have to be particularly fancy But that's kind of our setup here. So if I wanted to write a test for this, how would I go about doing that? If I go to Stripe's documentation, they have this really weird thing where they suggest uh putting in different card numbers. Um the idea is that I have different card numbers will return different values or different types of errors or different things when it's in test mode. And so if I pass in, you know, 24242424, $10. Uh oh a payment declined, you know, exception, that sort of thing.

23:28

Speaker 1: So that's sort of their recommended way of of testing this. That's sort of ridiculous. You know, it's sort of crazy that that's how we would have to test this thing. It's crazy because it would require us to make an external call to our API when we write our unit test. So that could be problematic. What happens if that API is down? What happens if that API doesn't work? Or what happens if we, you know, are just running into all kinds of connectivity problems? It's gonna make our tests fail intermittently and it's not not good It's also super unclear to people who are maintaining this what those numbers mean without them actually looking at the documentation. So imagine six months down the road you're looking at these unit tests, or someone else is looking at these unit tests. They'll see those card numbers and they're like, what does that mean? What does that do? You know, it doesn't make any sense to them. They have to go to the website and plug those numbers in.

24:14

Speaker 1: So you want to make sure that our code is really maintainable. And that's not gonna work for us. Also, we run the problem of the Stripe token. This is the one that's the bigger frustration for me. It's not just a dictionary of credit card fields, it's actually an encrypted token. So if I were to pass this thing in, I have to actually reverse engineer and kind of figure out what that value should be. And it's some sort of like encrypted hash. So I have to generate it and then I so talk about something that's like unmaintainable and unreadable. It's a little token of some kind that I don't know what that thing is. So that's no good. So clearly there's gotta be a better way to do this, right? We all know better now. Everybody here in the room knows there's a better way to do this, right? We tried mocking it, sure. Same idea here, we're using pretty much the same general pattern.

24:59

Speaker 1: We're gonna call that patch decorator, and we're gonna actually patch the uh the stripe charge. create method I'm gonna set up a sample uh card error, and the idea here is I'll just pass in whatever I want, you know, kind of set it up however I'd like to with whatever error messages I want to put in. And then I'm going to call our good friend side effect. Now you guys might remember this from earlier in the presentation. I said that side effect takes in a list, but it actually kind of does double duty. Side effect can take in an iterable object, but it can also take in an error or an exception. So in this case, if you give it an error, what it will do is whenever that method gets called, it will raise that exception. So it raises up and then we can catch it. So that's really nice because then you know I can call my method and verify that it actually has the correct behavior. I just pass it in that card error and that's it.

25:46

Speaker 1: So this is a very simple, very easy way for us to generate exceptions in our in our code and test all those branches. So let's uh let's talk about some of the takeaways here, right? Something easy. Just wrap this up for us. If there's nothing that you guys uh remember from this presentation, it's that mocking makes uh it solves three very specific cases for us. We eliminate dependencies, we verify behavior for things that have no return value, and we can generate errors on the fly if we want. The only thing that's kind of holding us back is we just need practice with this. You know, lots of examples. Hopefully you guys uh can make good use of that. If you want to try it out on your own, you've got the uh read the docs, very uh very good documentation there, lots of lots of information.

26:34

Speaker 1: I pulled most of the things From that. If you're using Python 2, you can just pip install it. If you're using Python 3, it's already built in, so it's already there, which is great. The way I learned was basically creating a bunch of simple test classes and trying it out and writing unit tests around it just to get practice. So let's go out and write some tests. Yay, do it. All right. Uh questions? Yes.

27:07

Speaker 2: Okay, so thank you very much for doing this topic. Um I have been searching like all of the web, all material I can find that is not specifically Java related. I've been trying to absorb, but it's explicit it's specifically about mocking and especially because when we're dealing with frameworks like Django And I mean it's obviously not alone and I know that there's that whole G Magicify Django initiative, but there's still a lot of magic. Yeah. And so what I've run into because I'm dealing with Django and not dealing with with you know the hot dog standard. Yes. Lyset, which is great for practice, but you know like we're talking about, all right, well, you know, there might be this uh you know image field type that is you know, part of another cloud uh model. And so it's just I how are

27:53

Speaker 2: what is a good source for looking for examples for um mocks that would really kind of need to be a bit introspective to do the right thing. Because I mean you have that situation where uh a model field for instance you know in the Django universe is it it can't be empty, you know, or you can't stand the model to actually do some tests on it. So

28:18

Speaker 1: Sure. So uh actually I thought uh I spent a lot of time thinking about this sort of problem. Uh this is a great question too, because it's sort of I I work with a lot of uh more junior developers and they say like well at what point in time is it like in Django land or like in sort of generic custom code land? And I asked them, you know, what thing are you trying to test? Are you trying to test the integration of how Django fits together or are you trying to test some custom logic that you wrote? In some cases it makes sense to use like Django's test runner, and sometimes it makes sense to use Django's client. Um, in other cases it doesn't. for like mocking out um models that have particular fields, you can put in like a you can uh give it a spec uh when you create your when you create your mock and that at least helps somewhat But in other cases it almost makes more sense to just use like Django's test runner

29:07

Speaker 1: test client and grab data from a fixture. So it's sort of like they're like, oh no, you're saying you said to only use mocks ever, you know, it's like, well Be pragmatic, right? If I'm trying to test something that I'm getting out of a database and it has a complex relationship that I want to test and I want to make good use of. That's not necessarily logic per se. It's custom, but we should be using uh we could be using uh the stuff that Django has built in. It makes sense there. It's more of a murky area. It's not a good, clear, and hard rule on like you need to just use this particular thing or only do it in this case. It's sort of If it makes sense and it's pragmatic, do it that way. If it causes you a lot of pain and effort, then you know don't do it. Does that make sense does that answer your question?

29:52

Speaker 2: Well I mean sort of only in so much is that it's like there are those scenarios where I really feel like it's my lack of knowledge, of how to do it, because you know there there are those cases where no, I really I would like that to appear as it needs or as as it's expected to be, but I'm not I'm not really trying to test that. If I did not have to then muck around with you know dumping files onto the disk or you know shoving stuff in the database because that's not the point for what I'm trying to test. Right. But I feel like it's like with that with with the framework that I almost get pushed towards that kind of almost you know hybrid integration unit test, but it's not really a unit anymore.

30:39

Speaker 1: Right, exactly. So it's because it's making calls to the database, because it's making calls to bits and pieces of Django, like I'm grabbing a setting or whatever, like you know, it's something that isn't really a unit test, it's more of an integration test. And at the end of the day, like um it's not it's not the end of the world. Like it's good to have integration tests, and it's it's perfectly okay to do that. You know, it's I mean you're writing tests, that's good no matter what, you know, you're making your code better. Um But it I I feel for you. I I have the same problem and I don't really have like a great solution for it, you know. I know, I know. Next next year uh we will work on this. Um but this is a great question, something I I've been thinking a lot about. Uh other questions?

31:20

Speaker 3: One question I would ask is uh I've spent a lot of time recently dealing with a lot of SOAP APIs or very heavy external reliance on services that aren't always documented for how they're gonna behave in certain instances. Do you have any kind of Tips or pointers on how to use mocking in order to make some of that stuff easier. One

31:50

Speaker 1: of the downsides of using a mock is that uh it will just allow you to call whatever on it. It just uh it will say like, oh that method, even if it technically should exist or should not exist, it'll say like, oh that's fine, you called it. I mean I don't know if it's there or not, but because it's uh it's a dynamic language. Uh when working with something where it's it's a little more like unknown or it's a little bit uh confusing of where you know what things should be, uh the best the best advice I guess I can offer on that is uh If it's uncertain, then uh make it something that's explicit in your test. So if the idea is like I don't actually know if these fields are there, So I I find this lot when I integrate with an API. Uh I'll integrate with other people who've written an API and it's like, well, it kind of works this way, but they don't have really strong documentation.

32:36

Speaker 1: And I want my stuff to be bulletproof. I want my stuff to be very, very you know concrete and well-defined. What you want is um your test to fail if that method or that thing doesn't exist there, right? So hey, this this method doesn't, you know, I was expecting that this thing would be there, I was expecting that this method would be available. But it wasn't. And then that forces a discussion between you and either the people who maintain the API or it raises a red flag for you and you go, oh crap, this thing was supposed to be there. It you know is an assumption that I had made that it would be there But uh I'm you know I I now have to rewrite some things to make sure that I accommodate that. Does that make sense? Cool. Uh other questions? Go for it.

33:21

Speaker 4: There's a create auto spec uh keyword argument which can help to back up, you know, preventing it from accidentally.

33:29

Speaker 1: Exactly. So Yes, thank you so much. The the create autospec uh will allow you to like it'll uh figure out what the methods are supposed to be on there and then if you try and call one that doesn't belong to that class. then it will it will uh raise an exception instead. So yes, excellent point. Thank you. Anyone else? Yeah.

33:49

Speaker 5: Do you yourself practice um like TED? in your you know you're just building on stuff or do you tend to write the code first, write the tests?

33:56

Speaker 1: I I tend to, to be honest, I tend to write my code and then I I write the tests. But this is sort of I was uh talking about this with a with a a junior developer and he was trying to learn trying to learn Django, trying to learn Python, and the challenge he kept running into was Uh he would he would try and write a test first, but he didn't really understand or know what the expected result should be. So because he didn't really know or understand what the expected result should be It was hard for him to write a test because he spent more time sort of noodling around and figuring it. And and what I wanted him to do was more experimentation and sort of, well, well, what happens when you call this? What does this do? And then verify your assumptions with testing I like that approach and I think that that makes a lot more sense and is less um less topsy-turvy. You know, it's it's uh easier for me cognitively to think about that.

34:45

Speaker 1: But uh in the TDD vein I would say work on a small section of code, stop and write tests for it to verify that that thing works. and then move on versus sort of writing the tests first, you know, and then trying to write your code. So it's sort of, it's not exactly TDD. I'm not an evangelist for it, but If you are writing tests in any capacity, I think you're at least doing uh something better for yourself. You're you're quantifiably making your code uh high quality.

35:16

Speaker 6: So uh I think we're we're sort of getting close to to this question with with your last answer, but one of the challenges with this kind of approach is that It makes it it's very like uh you have to know about the implementation in order to know what to mock, right? So you end up having kind of brittle tests that are associated with the implementation. way more than you might like. Do you have any strategies that you might recommend for avoiding that kind of problem?

35:40

Speaker 1: You say like brittle, uh can you clarify?

35:42

Speaker 6: Well I mean like You know that that get random person is being called by that function, right? So you have to know exactly what to mock inside the implementation of what you're testing.

35:56

Speaker 1: It seems to me like uh when I when I write tests, um some of it the at the end of the day I have to know how that method functions somewhat. You know, the the actual details of how it gets implemented can shift. But when I write a test, I'm sort of like saying uh setting in stone what I want this to be and how I want it to behave. So it's sort of a it's that point where the rubber meets the road. So I don't think it's necessarily brittleness. It's sort of like a um, okay, I am writing down in code exactly what I think this method should do and exactly how I think it should behave. You know, if I think it should call this method, it's going to call this method. And when somebody changes it to not call that method because they refactored it, that test will fail. And that's good. That forces that like, oh shoot, I changed something. You know, was this a valid test? Is this still a valid test? that we need to go through.

36:42

Speaker 1: So it's not necessarily, you know, obviously we're trying to capture some of the logic of it, you know, so uh in in the examples it's, you know I know these methods are being called, but they fill into the logic of my decision tree, you know, the things that I'm trying to test and the logic that I'm trying to put in. So sort of a it's a gray area of sorts, you know.

37:03

Speaker 7: I guess it in regards to some of the brittle problems, something that I've it depends on the problem, but a lot of times I'll have a fixture. And my mock will load a fixture that I've generated and I'll use a make file to document how I generated that fixture. But uh my question for you is, do you have any experience with mocking daytime? I've gotten it to work a few times. Oh boy. I always get it to work.

37:33

Speaker 1: Right.

37:34

Speaker 7: But uh there's a library that helps I've always managed to get it to work without resorting to installing another library. Just wondering what your personal experience is.

37:42

Speaker 1: No, actually I haven't I haven't worked with that surprisingly. So thank thankfully I have not been involved in like time zones and that sort of stuff. So um I unfortunately don't have any wisdom there for you, but uh Best of luck. I feel I feel your pain, you know. Um I I use

38:01

Speaker 3: arrow to get around that problem.

38:03

Speaker 1: Oh arrow. Cool, I'll have to check that out. So arrow for uh for using time zones. Cool, thank you. Um thank you guys.

Questions this talk answers

What is mocking in unit testing?

Mocks are test doubles used to replace dependencies, return controlled values, verify that methods were called, or simulate errors. The talk uses “mock” broadly to include stubs, spies, and mock objects.

Discussed at 3:21

Why should I use mocks in unit tests?

Mocking removes dependencies, reduces test complexity and runtime, makes otherwise nondeterministic behavior reliable, and lets you test code even when dependent components are unfinished. It is especially useful for database calls, external services, methods with no return value, and hard-to-trigger exceptions.

Discussed at 4:32

How do I mock a dependency in Python with patch?

Use `patch` with the module and attribute being replaced, then set the mock’s `return_value` to a known result. For methods on a class, use `patch.object`; the same replacement can also be done with direct assignment or a context manager.

Discussed at 11:00

How do I mock a method that returns different values on successive calls?

Set the mock’s `side_effect` to an iterable such as a list. Each invocation then returns the next value, which is useful for testing loops and retry-like behavior.

Discussed at 13:18

How can I verify that a method was called in a unit test?

Mocks record their calls, so you can check `call_count` or use `assert_called_once_with` to verify both the number of calls and the arguments. Multiple dependencies can be patched by stacking decorators or using `patch.multiple`.

Discussed at 16:26

How do I check the arguments for a method called multiple times?

Use the mock’s `call_args_list`, which contains the arguments for every invocation, and compare each entry with the expected call arguments in order.

Discussed at 20:21

How do I test code that handles an exception without causing the real error?

Assign the exception to a mock’s `side_effect`. When the mocked method is called, it raises that exception, allowing the test to exercise the error-handling branch without relying on external conditions such as a declined payment or a failing API.

Discussed at 24:59

Should I mock Django models, or use Django’s test tools instead?

Use mocks for custom logic when replacing a dependency makes the test clearer, but use Django’s test runner, test client, or fixtures when testing Django integration or complex database relationships. The speaker recommends being pragmatic rather than applying an absolute rule.

Discussed at 28:18

How can I make mocks fail when an API method or attribute does not exist?

Use a mock with a specification, or use `create_autospec`, which derives the allowed methods from the real class or object and raises an exception when the test calls something that is not part of that interface.

Discussed at 33:29

Is it better to write tests before or after the code?

The speaker usually writes the code first, then tests small sections to verify them, rather than strictly following test-first development. He emphasizes that writing tests in any useful capacity improves code quality.

Discussed at 33:56

Presenters

Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.

More videos from DjangoCon US