We know our unit tests should be relatively independent from other parts of the system. For example, running a test shouldn't generally call a credit card possessing API and talk to a database when your goal is just to test the argument validation.
And yet, your method does all three of those and more. What do you do? Some languages use elaborate dependency passing frameworks that go under the banner of inversion of control (IoC) and dependency injections (DI). In Python, the most common fix is to temporarily redefine what those two functions do using patching and mocking.
On this episode, we welcome back Anna-Lena Pokes to talk us through the whole spectrum of test doubles, dummies, mocks, and more.
00:00 We know our tests should be relatively independent from other parts of the system.
00:03 For example, running a test shouldn't generally call a credit card processing API and talk to a database
00:09 when our goal is just to test the argument validation.
00:12 And yet, your method that you want to test, it does all three of those things and more.
00:17 What do you do?
00:18 Some languages use elaborate dependency passing mechanisms and frameworks
00:23 that go under the banner of inversion of control and dependency injection.
00:27 In Python, we do sometimes have that, but it's much more common to just temporarily redefine
00:33 what those two functions do using patching and mocking.
00:36 On this episode, we welcome back Annalena Popkas to talk us through the whole spectrum of
00:42 test doubles, dummies, mocks, and more.
00:44 This is Talk Python To Me, episode 287, recorded August 24th, 2020.
00:50 Welcome to Talk Python To Me, a weekly podcast on Python, the language, the libraries, the
01:08 ecosystem, and the personalities.
01:09 This is your host, Michael Kennedy.
01:11 Follow me on Twitter, where I'm @mkennedy.
01:13 Keep up with the show and listen to past episodes at talkpython.fm.
01:17 And follow the show on Twitter via at talkpython.
01:20 This episode is brought to you by Linode and monday.com.
01:23 Please check out what they're offering during their segments.
01:25 It really helps support the show.
01:28 Do you want to learn Python, but you can't bear to subscribe to yet another service?
01:32 At Talk Python Training, we hate subscriptions too.
01:36 That's why our course bundle gives you full access to the entire library of courses for
01:40 one fair price.
01:41 That's right.
01:42 With the course bundle, you save 70% off the full price of our courses, and you own them
01:47 all forever.
01:48 That includes courses published at the time of the purchase, as well as courses released
01:53 within about a year of the bundle.
01:54 So stop subscribing and start learning at talkpython.fm/everything.
02:00 Anna Lena, welcome back to Talk Python To Me.
02:03 Thanks.
02:04 It's great to be back.
02:05 Yeah, it's super to have you back.
02:06 Last time we spoke about 100 days of code and Harry Potter and things like that, if I recall
02:13 correctly.
02:13 Is that right?
02:14 Yes, that's correct.
02:16 Yeah, that was really fun.
02:17 And that was right at the height of the 100 days of code when everyone was really using
02:21 that to learn to code.
02:22 And so you had this unusual, but I think really engaging way of taking code and making it not
02:27 just silly technical stuff, but making it this fun Harry Potter adventure world.
02:31 Yeah, I still love that approach.
02:33 So I always try to find something I'm passionate about and then trying to use it to learn.
02:39 Yeah, excellent.
02:40 So now we're going to come back and talk about writing code that we're more likely to be
02:46 sure that works, testing code and using mocking and all that.
02:49 But when we spoke last time, you were a, was it an internship at Microsoft?
02:55 What kind of?
02:56 It's something in between.
02:57 It was called an AI residency at Microsoft Research in Cambridge in the UK.
03:02 So it's like an intensive one year program where you learn a lot about how to apply machine
03:07 learning, how to become a great research engineer.
03:09 So cool.
03:10 It's like, yeah, it's more than an internship, like a really long extended internship.
03:16 I'm sure that was a really fun project experience.
03:19 Oh yeah, it was amazing.
03:21 Also the place Microsoft Research in Cambridge is just great.
03:25 I really loved it there.
03:26 Yeah, I can imagine.
03:28 And how about now?
03:30 What are you up to now?
03:31 Yeah, so I finished the residency and I moved back to Germany and joined a German company
03:35 called InnoVex.
03:36 I also like it here a lot.
03:38 And I'm working as a machine learning engineer, similar to what I did at Microsoft Research,
03:43 but not so research heavy.
03:46 So I'm doing more production code or production work.
03:50 And I'm currently working in a pure data engineering project.
03:53 So I've been learning a lot more about the work that comes before actually applying the machine
03:57 learning algorithms, which is also very interesting.
04:00 Yeah.
04:00 So I would guess that involves a lot of pandas, a lot of cleaning up data, like getting stuff
04:04 in the right format.
04:05 Yes.
04:07 Yeah.
04:07 And then we give the data to the data scientists, which can just use the clean data to do their
04:12 nice machine learning stuff.
04:14 Yeah, you make them look good.
04:16 You're like, oh, here, you just feed this over and it works great.
04:18 Like it didn't start out that way.
04:21 What kind of problems are you trying to solve or answer?
04:23 It really depends on what the customer wants.
04:26 So it can go from supply chain management and apply machine learning there to right now in
04:32 the cloud, where we just create kind of a data lake in the Google cloud, where we have different
04:38 data sources that have to be processed and brought together and all the other stuff.
04:44 So there's just a lot going on.
04:46 It's a very huge project with several teams working on it.
04:49 Wow.
04:49 Yeah.
04:50 It sounds really fun.
04:51 And it sounds like one of these big data projects that people talk about a lot, but not
04:55 that many people actually do.
04:56 Yeah.
04:57 And it's also very interesting for me to see this other side.
05:00 I've been working on machine learning for most of my computer science life.
05:04 So seeing something different is also always very nice.
05:08 Yeah, absolutely.
05:09 And you also have some project going on in your spare time, yeah?
05:12 Yes, exactly.
05:13 So Kai Macht Schule.
05:15 Yeah, it's I think like it's a German project.
05:19 I'm doing voluntary work there.
05:21 It's called Kai Macht Schule.
05:22 That's like, I think you could translate it as AI goes to school.
05:27 Yeah, where we teach AI and machine learning skills to kids in German schools.
05:31 So we do classes usually on site, but now online due to the COVID crisis.
05:37 And yeah, it was somewhat similar to what you talked about in the last episode or some recent
05:43 episode with Nick Winter on Code Combat.
05:45 Yeah, Code Combat is really a fun thing for kids as well.
05:49 I think that's super neat what they're doing.
05:51 I want to try it as well, even if I know how to write code in Python.
05:55 It sounded so much fun.
05:56 Yeah, it's really neat.
05:58 I really enjoyed just kind of poking around with it and seeing it's, again, kind of like
06:03 your Harry Potter world.
06:04 It's a very different way to present programming to kids where you still type.
06:08 It doesn't feel like the burden of being exactly right.
06:11 You can kind of type it wrong and it'll mostly correct it for you.
06:15 So it's pretty interesting.
06:16 So with this project, you're teaching kids AI and machine learning.
06:21 What does that even look like?
06:22 What kind of stuff are you teaching them?
06:24 What do they get when they're building little libraries and so on?
06:27 Yeah.
06:27 So we try different approaches.
06:29 We always have a bit of theory.
06:31 So what is AI?
06:33 How does it work?
06:34 We also have a part on the ethics behind AI, which I think is really important.
06:39 And there's also some practical exercises with Jupyter Notebooks.
06:43 Before we used an approach was where you have these blocks of programming parts, which you
06:49 can stick together, like the for loops and so on.
06:52 But we didn't like that so much.
06:54 So right now we are using Jupyter Notebooks.
06:57 And I think it's amazing since right now there's one, it's called KI Camp.
07:01 It's like a four-day course.
07:02 And the youngest one is in fifth grade.
07:06 So it's like 11 or 12.
07:08 And the oldest one is just about to graduate.
07:10 And it's so nice to see these kids fascinated by this topic.
07:14 Yeah.
07:15 It's definitely going to give them a leg up, learn these types of things early and know
07:19 about them and just to learn about Jupyter and computational thinking at all.
07:23 Yeah.
07:23 And Germany is also really not so good with the computer science work in school.
07:28 I think in the US you are much better with teaching kids how to code in school already.
07:34 For German kids, it's really hard to get to know AI or to find somewhat a way to get familiar
07:41 with the topic without going out there and looking for yourself what's out on the internet.
07:48 Yeah.
07:48 There's the small percentage of kids who will do that.
07:51 They'll go find it themselves.
07:51 But the majority don't even know they would be interested until they get exposed to it.
07:56 Exactly.
07:56 Yeah.
07:57 It was the same for me.
07:58 So that's why I'm really passionate about this project.
08:01 Yeah.
08:01 Awesome.
08:02 And you've definitely taken it quite far what you're doing these days.
08:04 That's definitely the pinnacle.
08:06 It's great.
08:06 All right.
08:07 Well, let's focus on our main topic for a little while on mocking.
08:12 So how'd you get interested in it?
08:14 How'd you get started?
08:14 Yeah.
08:15 So I stumbled upon this topic a few months back when I started working in this data engineering
08:20 project I was just talking about.
08:21 And we have lots of production code there.
08:24 And I never heard of mocking before.
08:26 So it was the first time I used it.
08:28 And since then, I've been using it in almost all of the tests I write.
08:32 It's a very controversial topic.
08:34 So I watched quite a few PyCon talks on it and read quite a few blog posts.
08:39 And yeah, it's just a big but very interesting thing to talk about.
08:45 Yeah.
08:45 So I think one of the controversies has to do with you can write your code in certain ways
08:50 so it's more easy to test or it's harder to test.
08:53 And some people see mocking as kind of covering over the bad code you've written or something
09:00 to that effect, right?
09:01 Hopefully that sort of summarizes it.
09:03 Yeah, exactly.
09:04 And I completely understand that.
09:06 So you shouldn't use mocking to fix your badly written code.
09:10 So you, of course, you should first think about, is my code good?
09:14 Do I want to refactor it?
09:16 Are there changes I can make to make it easier to test?
09:20 But sometimes it can be a really good tool.
09:23 I think it's a great tool.
09:24 I think when it's used in the right ways and right places, it's just what you need.
09:28 Yes, I agree.
09:29 Yeah.
09:29 I mean, Python is so much about the sort of practicality beats purity.
09:34 You know, it's part of the Zen of Python and all that.
09:36 And it's just, let's just do what we need to do to make stuff work.
09:41 And I think one of the examples where this is really different from other languages is in
09:45 Python, we don't have things like protected variables.
09:49 We don't have as often like concrete interfaces.
09:53 We don't have type enforcement, right?
09:55 Like the thing you passed here must be this interface.
09:58 And if it's not, we're going to raise an exception.
10:00 We have type hints, but that's like an editor or like tool helper.
10:04 It doesn't mean that runtime it's not going to work or it won't compile or whatever.
10:08 Yeah.
10:08 Right.
10:09 And so I feel like mocking and patching is like, it's sort of, it's more embraced in this
10:15 world where it's like, look, if we just do this little thing, we can avoid all this complexity
10:19 and all of these design patterns and all of this stuff that technically would be maybe a
10:24 more official, pure computer sciencey way.
10:27 But if you look at the stuff that gets built from it, it gets really hard to deal with it
10:31 and ugly.
10:31 Yeah.
10:32 Yeah.
10:33 I agree.
10:33 Yeah.
10:34 I remember I worked on this one project and it was originally written, I think in Java
10:39 and then converted to C#.
10:40 And it used, I think every design pattern that you could possibly name.
10:44 And it used every single thing that used some sort of dependency.
10:49 It had an interface for that dependency.
10:51 It would pass that in into the constructor.
10:53 And then when it created objects, it would pass that further down.
10:56 And what you ended up with was the entire code that you wrote was all this abstract stuff.
11:01 And you would look at it like, well, I see all the functions, but I just don't even know
11:06 where I would go to find out what actually does this.
11:09 It's just, it was so insanely complicated.
11:12 So I've seen that far in and I've seen the world where people just go, you know, okay, we're
11:17 not going to set up all those structures, but we're just going to do a patch like deep down
11:21 inside of some function call.
11:23 And if I had to pick one of those two worlds, I would definitely live in the world where
11:27 we just keep things simple as it's, it was not fun to work on that project in that way.
11:31 It sounds terrible.
11:33 Yeah.
11:33 Yeah.
11:34 It was like a, probably a six month project.
11:36 I'm just like, I'm constantly frustrated on this project.
11:38 So let's, I guess, start at the beginning.
11:42 Like what is mocking?
11:44 There's a lot of folks who listen, who come from a sort of scientific background where they
11:48 haven't done official computer science or they're self-taught.
11:51 Maybe, maybe this idea is new to them.
11:52 What is, what's mocking?
11:53 Yeah.
11:54 So a mock simulates the existence and behavior of a real object.
11:58 I guess we can go over a few examples, but if you use mocking, you as a developer can
12:04 improve the quality of your tests and also test code in a controlled environment.
12:08 And it's especially useful if you have external dependencies, like if you want to write to a
12:13 database or do stuff like that.
12:15 And there's a nice Python library, which is included in unit test, which is called unit
12:21 test.mock, which can be used for mocking.
12:23 I think there are also some more specialized libraries out there.
12:27 I think there's one, especially for mocking date time, but I've never used it.
12:32 So I'm only using unit test.mock.
12:34 Yes.
12:35 I think the one out there called that is called freeze gun.
12:38 Yes, exactly.
12:40 Yeah.
12:40 That's it.
12:40 Yes.
12:41 A freeze gun.
12:42 And that one basically, you know, like you said, allows you to control the date time module.
12:48 So there's obvious dependencies that you would think of.
12:52 Like if I have a traditional web application, maybe it calls some API, like my online courses
12:58 thing.
12:58 It's going to call Stripe.
13:00 It's probably going to call MailChimp APIs, does some other stuff.
13:03 It's going to talk to a database.
13:05 So when you think about dependencies, you think, okay, database, maybe the file system,
13:09 external APIs, and those are all things you can mock and you probably want to.
13:13 But when I first got into this world, one of the things that really surprised me was how
13:18 hard it is to work with time.
13:20 If I want to say, I would like to call this thing before, like, let's just say it's e-commerce.
13:26 Like I want to make sure that this discount code is not expired now.
13:29 So it gives me the discount, but in a week it will be expired.
13:32 You know, like that's really hard to deal with.
13:34 Right.
13:35 Yeah.
13:35 I think that's a very good place to use mocking for like, it's a great example for that,
13:40 where it can be really useful.
13:41 Yeah.
13:42 And the alternative, I talked about this dystopian world that I lived in for a while.
13:46 The alternative would be, you would have to create a fake class that read, like that you
13:52 used to get what now is, right?
13:55 Instead of just saying datetime.now, you have to create a class like time provider now, and
14:01 then everybody has to agree to not use datetime.now, but they'll have to share
14:05 this other thing that you're going to pass around.
14:07 And that's just, that's just crazy.
14:08 Right.
14:08 Like it makes no sense.
14:10 Yeah.
14:10 It's unnecessarily complicated.
14:11 Yeah.
14:12 It's just so complicated.
14:14 And so you can, if you just mock out what now means.
14:18 That's it.
14:18 Yeah.
14:18 Then you're good.
14:19 It's fixed.
14:20 Right.
14:20 So yeah, it's pretty cool.
14:22 And Freezegun is one of the libraries.
14:23 I'm sure there's a bunch out there, but that's a cool one for doing this kind of stuff with
14:27 specifically with time.
14:30 This portion of Talk Python To Me is brought to you by Linode.
14:33 Whether you're working on a personal project or managing your enterprise's infrastructure,
14:37 Linode has the pricing, support, and scale that you need to take your project to the next
14:41 level.
14:42 With 11 data centers worldwide, including their newest data center in Sydney, Australia, enterprise
14:47 grade hardware, S3 compatible storage, and the next generation network, Linode delivers the
14:54 performance that you expect at a price that you don't.
14:56 Get started on Linode today with a $20 credit and you get access to native SSD storage, a 40
15:02 gigabit network, industry leading processors, their revamped cloud manager at cloud.linode.com,
15:08 root access to your server, along with their newest API and a Python CLI.
15:12 Just visit talkpython.fm/Linode when creating a new Linode account and you'll automatically
15:18 get $20 credit for your next project.
15:20 Oh, and one last thing.
15:22 They're hiring.
15:22 Go to linode.com slash careers to find out more.
15:26 Let them know that we sent you.
15:27 So you talked about replacing dependencies.
15:31 I guess give us some more examples.
15:34 Time is one that maybe doesn't first come up, but what are some of the type of dependencies
15:37 you all were working with?
15:39 So I've been working a lot with the Google Cloud client.
15:42 So where you want to write or either you want to communicate with the Google Cloud with
15:46 different services there, or you want to write to the storage and you need to someone, you
15:52 have a client and you want to communicate with the Google Cloud.
15:55 And that's the part where we mostly use mocking.
15:59 So to somewhat make sure that we test that the file is written, or at least that we have
16:05 the correct paths, the correct function call, but we don't actually want to write the file
16:10 to the Google Cloud every time or remove it.
16:13 Right.
16:14 You know, cloud computing, I think it has a really interesting challenge around testing.
16:20 It just, in a lot of ways, right?
16:22 Like you don't, if you're going to work with the API, you obviously have to not talk to the
16:26 real API.
16:26 You don't really want to create a virtual machine or a Kubernetes node or whatever, but you do
16:31 want to test that that code's going to work.
16:33 But at the same time, a lot of times the tests depend on something meaningful coming back.
16:37 Yeah.
16:38 Right.
16:38 There's so much going on in the cloud side that I think it's pretty tricky.
16:43 Do you guys do anything special there?
16:44 Like I know in AWS, there's like a fake local AWS type thing you can run.
16:49 And I know I've talked about it a while ago and I forgot what it's called, but do you guys
16:53 do anything like that?
16:54 Not at the moment.
16:55 I think someone is working on finding ways to improve this since we are using mocking
17:00 quite a lot, but it's a really complicated and complex thing since we have a huge code base
17:06 already and you would have to change all the code again.
17:08 So doing kind of refactoring at this point is always a big deal.
17:14 But right now we are just...
17:16 Yeah, it might not even be worth it.
17:17 Yeah.
17:17 Yeah.
17:18 Yeah, exactly.
17:19 Yeah.
17:19 And I think there's also something to be said for that, right?
17:22 Like sometimes it's like we could create a mock or fake or we'll talk about the different
17:27 terminologies here in a minute.
17:28 Yeah.
17:29 But sometimes it's like, you know what?
17:31 I'm just going to let it ride to the file system.
17:33 It's not the end of the world.
17:34 We're going to keep going.
17:35 One of the really tricky ones I think has to do with data access, right?
17:41 I'm going to go talk to the database and get this and then I need to get this other thing
17:44 that's related to that.
17:45 And I think it's a constant challenge to figure out how much of that you replace and how much
17:50 of it you just test against the database or test against a file or something.
17:54 Yeah.
17:54 It's sometimes difficult to find the right way.
17:56 Also, if you are working in a team and other like different people have different opinions
18:01 and like different things, but there's also a middle ground somewhere.
18:05 Yeah, for sure.
18:06 Yeah.
18:06 I could see one person on the team is all about like we have to do it the right way where there's
18:11 no external dependencies.
18:12 And the other person's like, we also have to get stuff done.
18:14 You know, I also have to.
18:16 I can't spend all my time recreating all of these systems that you're trying to talk
18:20 to in ways that are sufficiently accurate so that when you call them, the test data comes
18:25 back, but it's as accurate or realistic enough that you're really getting a meaningful test.
18:30 So it's tricky.
18:31 So you have a example class speaking of Harry Potter and all that.
18:36 Yes.
18:37 That we're going to use.
18:38 We're going to kind of build up some ideas.
18:40 And it's always hard to talk about code in audio format.
18:42 So we'll keep it simple.
18:44 But maybe just give us a quick introduction.
18:46 Yeah.
18:47 So we have very simple spell class, which where you have just the constructor in the beginning.
18:53 And a spell has, of course, a name.
18:54 It has an incantation and a description.
18:57 So for example, I think there's Accio in Harry Potter, where it moves an object towards the
19:05 person who is casting the spell.
19:08 And a description could be what I just said.
19:11 And then you have the incantation.
19:12 Yeah, moves object towards person.
19:14 Yeah, exactly.
19:14 Exactly.
19:15 So that would be an example.
19:16 Okay, cool.
19:17 All right.
19:18 So we'll build up on this as we go through these different ideas here.
19:21 And we've been talking about mocking as if it's all kind of the same.
19:26 But if you dig into it, there's actually like a spectrum of ways in which you can do mocking.
19:32 One of those might be, I just, when I call this function, I want it to not write to the
19:38 log on the file system.
19:39 And it might be enough that it just doesn't do that.
19:41 You don't care what it does.
19:43 It just doesn't do that.
19:44 On the other hand, there's like very advanced, tricky usage.
19:48 Like when I call this function, I want to make sure that it checks whether the person is an admin.
19:54 If I say yes, I want to do one thing.
19:56 But I want to make sure that it actually always, always calls this function to make sure that it
20:00 checked for them, even though you couldn't observe that as a side effect.
20:04 I want to make sure that it's like calling this once and this twice or in this order.
20:08 Like there's a lot of tricky things.
20:10 And those feel like very different things.
20:12 So in the mocking world, there's different names for these things, right?
20:16 Yes.
20:16 And there's also disagreement, I guess, about the terminology and also the definitions of
20:22 these different kinds of mocking behaviors that you can distinguish.
20:25 Yeah.
20:26 And it may or may not be useful.
20:28 Like people can decide how much they care about being very precise about calling it one thing
20:33 or the other.
20:34 But yeah, let's talk about it in the fine grained view, just so people get the full exposure
20:40 and they can decide to ignore the differences if they want, right?
20:43 Yes, I think that's a good idea.
20:45 So yeah, I think the overall name or the name for these kinds of mocking behaviors is called
20:52 test doubles.
20:52 So there are the fine grained view objects, which are not real, can be either dummies,
20:59 fakes, stubs, mocks, or spies.
21:02 And all of these are so-called test doubles.
21:05 Yeah.
21:05 And as I just said, these definitions are also controversial.
21:09 And there are sometimes so different sources describe them slightly differently.
21:14 But I think it's still possible to get an idea of what they are about.
21:19 Yeah.
21:19 Yeah, absolutely.
21:20 So let's start, I guess, at the simple side of things.
21:24 I feel like this whole concept has a little bit of a I'm making fun of you thing.
21:29 So mocking to like insult somebody.
21:31 And then you've got dummies, you've got fakes.
21:34 So let's start with the dummies.
21:37 Yeah, I think the dummies are the easiest to understand.
21:40 I agree.
21:41 Yeah.
21:41 And a dummy is just an object which is passed around, but never actually used.
21:46 So a dummy is not intended to be used in your tests.
21:49 And it does not have any effect on the behavior of the test.
21:52 And an example would be when you have attributes that you need to instantiate a class,
21:58 but you don't really care about what they are.
22:01 For example, for the spell class, if you need a spell instance in your tests,
22:06 but you don't care about the description, then you could just pause in an empty string or write whatever you want to in that string.
22:14 And that would be then a dummy.
22:15 Right.
22:15 If you don't supply it, it's going to crash.
22:17 Yes.
22:18 But you don't actually ever use it or care about it.
22:21 You just have to make it get out of the way and keep working.
22:23 Yes.
22:24 Yeah.
22:24 Okay.
22:25 So that's dummies.
22:27 Next up is fakes.
22:28 Yes.
22:29 So a fake implements a fake version of a class or method.
22:32 It has a working implementation, but it takes some kind of shortcut such that it's not suitable
22:38 for production.
22:39 And that could be in a memory database.
22:42 So usually in production, you would have a database that you write your files to.
22:47 But during testing, you could have some in-memory database that you only use during your tests.
22:53 Yeah.
22:53 That makes a lot of sense.
22:54 And that's definitely one of the tricky things, I think, is databases.
22:58 The other one that would be really tricky would be, say, an API call.
23:03 Like, for example, one of the things I have to do in my code is I have to figure out where
23:08 is this person located physically so that I can pick the right video server to deliver
23:14 the fastest video to them.
23:16 And so there's a call to go to the API that tells me where they are based on their IP address,
23:21 like what country basically they're in.
23:23 So I can work out what one to send, right?
23:26 Every time I run a test, I don't want to call that API, right?
23:30 Yeah.
23:30 And I don't really...
23:31 That's also a good example.
23:33 Yeah.
23:33 And I mean, probably the test doesn't actually care where it said they were.
23:36 But it's, you know, it's going to have to have some kind of behavior because it's going
23:40 to have to return a value so the program works.
23:42 Like, so maybe I could come up with a mock or a fake specifically that says whenever they
23:48 ask where they are, they're always in Kansas City.
23:51 It doesn't matter where they really are.
23:52 Just tell them it's in Kansas City so that something can happen where the thing keeps working,
23:57 right?
23:57 Yes.
23:58 That's also somewhat a good introduction of the next one, Stubs.
24:02 Stubs returns.
24:04 It has some pre-programmed behavior.
24:07 Most of the times they simply return fixed values or canned data.
24:11 Like you just said, for example, always return Kansas City.
24:14 And yeah, let's look at the spell class again.
24:18 Maybe the spell class could have a method get similar spells, which searches some database
24:24 and then you would get similar spells back.
24:27 And this is, of course, quite complex since finding these similar spells will probably be very difficult.
24:33 And you would.
24:34 Right.
24:34 Maybe the real version is running machine learning or some sort of crazy system.
24:40 And you don't want that to happen all the time, right?
24:42 Yes.
24:43 Since it would probably slow down your whole testing.
24:45 And then you could just replace the real implementation with a stop that returns hard-coded values and would only take a fraction of the time to complete.
24:55 Yeah.
24:55 Yeah.
24:56 That seems like a really good example there.
24:58 So I don't know.
24:59 I do have a hard time knowing exactly.
25:01 Okay.
25:02 I've got this idea of which one does it fit into.
25:04 It's almost like a spectrum saying that color is purple and that color is red.
25:10 What is the color that's purple but sort of towards red?
25:13 You know what I mean?
25:14 Yeah.
25:15 Yeah.
25:16 Cool.
25:17 All right.
25:17 So making our way across this rainbow, I guess, we have mocks.
25:21 Yeah.
25:22 So mocks are closely related to stops.
25:24 And there's this huge stack overflow post on the differences between mocks and stops.
25:29 And there you can also get a bit of an idea of the controversy surrounding this topic.
25:35 But yeah.
25:36 Yeah.
25:36 And I'll put that link in the show notes so people can find it.
25:38 Yeah.
25:39 That's a good idea.
25:40 So a mock does not have predetermined behavior, which stops have.
25:44 Instead, it has to be configured.
25:46 So an important difference between mocks and stops is that a mock records which calls have
25:52 been executed.
25:53 So it can be used to verify not only the result.
25:56 That's something that a stop can do too.
25:59 But a mock can verify how the result was achieved so that the correct methods have been invoked
26:05 on the mock object.
26:06 Yeah.
26:06 And this is where it starts to get complicated, I think.
26:10 One of the ideas of just programming in general functions and classes, but also testing is
26:16 you shouldn't depend upon the internal implementation of a thing when you're testing it or calling
26:24 it from the outside.
26:25 So if I have a thing that says register a new user, maybe I want to just check if I give
26:30 it valid information, it gives me a new user.
26:32 If I give it like a malformed email, it'll give me an exception, right?
26:36 Like that would be totally straightforward.
26:38 But all of a sudden with the this level of mocking, you're like, well, I want to make sure that it checks that the user is not already existing, that this other thing is happening.
26:48 And then you're getting more and more tied to the internal details of what that piece is doing, which is fine, maybe.
26:55 But then you change your code.
26:56 And all of a sudden, all your tests break.
26:58 You're like, well, now we got to go rewrite these tests because we don't have this thing that we were
27:01 checking that got called inside and it gets this sort of they kind of get glued together a little bit more, which I think can make maintenance hard.
27:10 Yeah.
27:10 Yeah.
27:11 We had that problem, too.
27:12 So, yeah, that's something you have to think about, too.
27:15 But at the same time, there's good uses for this.
27:18 Like I came up with that admin example, because one of the things that scares me a lot is you've got some protected part of an API or an application or something.
27:27 And somebody forgets to check whether someone is permitted to go in there.
27:32 That's really bad if that ever gets discovered.
27:34 You know what I mean?
27:35 Like, oh, did we forget to check in the show me all the users and their private information part?
27:40 We forget to check if you're logged in.
27:42 Whoops.
27:43 You know, that kind of stuff could totally happen.
27:45 And with this, you could say you are going to have a test for every one of these admin pieces that says you checked whether or not they were an admin.
27:52 Right.
27:53 That function was called no matter what.
27:55 Right.
27:55 Yeah.
27:56 Yeah.
27:56 This portion of Talk Python To Me is sponsored by Monday.com.
28:02 Monday.com is an online platform that powers over 100,000 teams daily work.
28:07 It's an easy to use, flexible and visual teamwork platform beautifully designed to manage any team, organization or online process.
28:15 Now, for most of us, we missed our chance to build the first apps ever in the mobile app stores.
28:20 It was a once in a lifetime opportunity, but it's one that's coming around again.
28:25 Monday.com is launching their marketplace and running a contest for the best new apps featured right from the get-go.
28:31 Want to be one of the first in the Monday.com apps marketplace?
28:35 Start building today.
28:36 They're even giving away $184,000 in prizes, including three Teslas, 10 MacBooks and more.
28:43 Build your idea for an app and get in front of hundreds of thousands of users on day one.
28:47 Start building today by visiting Monday.com slash Python or just click the link in your podcast player's show notes.
28:56 And so, these mocks, I think that's the thing you could do, right?
28:58 You could say, like, expect that this was, what is it, assert called once or something like that, right?
29:03 Yes, there are different kinds of assert calls there.
29:05 Okay.
29:06 We can talk about this later as well.
29:07 So, there is assert called once.
29:09 You can assert that was called with certain arguments, that it was called not called, that it was called, like, independent of the number of times.
29:18 So, there are kind of different things you can do.
29:21 And that can be very helpful.
29:22 Right.
29:23 I forgot about that.
29:24 You have the reverse as well.
29:25 You can say, I want to make sure in this situation, it never, ever calls this other function.
29:29 Yeah.
29:30 Right.
29:31 Right.
29:31 Yeah, that's true.
29:32 That would be another good type of test.
29:34 Okay.
29:34 So, that's mocks.
29:36 And then we have spies, which is next level stuff.
29:39 Yeah.
29:40 Yeah.
29:40 I find them really hard to grasp.
29:42 So, I haven't used spies yet myself.
29:45 But from what I read, it's that spies are used to wrap real objects.
29:50 And by default, they route all the method calls to the original object.
29:54 So, they somewhat intercept and record all calls that are made to the real object.
30:01 Yeah.
30:01 Okay.
30:02 So, this sounds like you might want to do those verification things that I was talking about, but not actually change the implementation.
30:09 Just let it do what it's going to do.
30:11 But you can kind of record that all the stuff was interacted with in certain ways or something like that.
30:17 Yeah.
30:18 It's kind of, it's a bit similar to a mock in that sense that you can assert that certain things are called, but it does not replace the original object.
30:27 That's what mocks are doing.
30:29 Yeah.
30:29 One of the tricky things with a lot of these, and the more you use them, the more you have to deal with it is, well, they're going to call this function.
30:37 So, what are you going to return from them, right?
30:39 So, if they're going to ask, is admin, well, you have to say, if they call, is admin, return true or return false, right?
30:46 And so, you have to sort of, at the beginning of your test, you have to configure the mock to say, they're going to try to do these four things to you.
30:54 Here's the answer.
30:55 Here's the return value.
30:56 Throw an exception if they try that or something along those lines.
31:00 Exactly.
31:00 Yeah.
31:01 That said, I think it's, you know, there's certain types of errors you want to test for that are really tricky, right?
31:07 Like, I want to see a SQL operational error.
31:10 Like, hmm, how am I going to make it do that without talking to the real database?
31:16 Well, you could come up with a mock that just says, if they call connect, throw this exception right away, right?
31:21 Like, that would be a good example, I guess.
31:23 Definitely.
31:24 Okay.
31:24 So, we have this spectrum of mocks, the dummies, the spies, the fakes, and so on.
31:30 When should we use them?
31:31 So, you can use a mock.
31:33 Like, I'm not talking about a mock, not all of the other things, but I guess it depends on whether you want to all call them mocks or not.
31:42 But, yeah, you would use mocking whenever you don't actually want to call an object.
31:46 For example, when you have the spell class and you want to, or you have a function in that class that saves some version of the spell, for example, as a JSON file,
31:56 and you have a function remove, which deletes that file again.
32:00 Then when you test those methods, you don't actually want to write the file to disk every time the test runs.
32:07 And the same holds for functions that remove objects.
32:11 But that's just one example of many things that you, where you could use mocks when you don't actually want to do the operation that you're testing.
32:21 Yeah.
32:21 Basically, when any behavior of the system is in the way of you testing it, either that's you just don't want to call an API, or you just don't want to write to the file system, or something like that, right?
32:32 Yeah.
32:33 Yeah.
32:33 I guess the other one is, if you need to reach down inside the system and make it do something unexpected.
32:39 Like I said, if you want the connect call to throw a SQL exception, it's hard from the outside, potentially, to set it up in that way.
32:47 But with a mock, you can just say, if they call this function, throw this exception, see how the system deals with it, right?
32:52 Yeah, that's also a very good use case.
32:54 Yeah, I think testing errors, a lot of people don't test for errors.
32:58 I feel like they're like, okay, well, this is what it's supposed to do, so let's test that.
33:01 And I think testing for the opposite is almost as important.
33:05 Yeah, definitely.
33:06 I agree.
33:06 Yeah, yeah, yeah.
33:07 Cool.
33:09 So when I look at mocking, there's actually multiple ways to do mocks, and I honestly don't know when I should be using them.
33:16 Yeah, so there are three core functionalities in the unit test.mock library.
33:20 One is the class mock, one is the class magic mock, and then there is the patch function.
33:26 And those have different properties, but maybe we can just go through them one by one.
33:32 I think that's the easiest.
33:34 Yeah, yeah.
33:35 Well, if you think, okay, I'm going to mock something, you probably would start with the mock class, right?
33:38 That's where you think you would start.
33:40 Yeah, I think that's the best start.
33:41 So you can use the mock class to mock any object, where the mock object, so the class instance, just simulates the object it replaces.
33:52 And I love this, since it's also kind of magic, since the mock, to achieve this, to really simulate the object, it creates attributes on the fly.
34:01 So when you, let's say you import the unit test.mock library, and you create an instance of the mock class, and then you can just call some attribute on it.
34:11 Let's call it fancy attribute.
34:12 And it was just create a child mock and return it to you.
34:17 So it would create this fancy attribute on the fly.
34:20 The same holds for any kind of method, and you can call methods with different kinds of inputs, so you can just do whatever you want to do.
34:29 And I really like that.
34:30 I find that really fascinating.
34:32 Yeah, it's quite interesting.
34:33 And you don't have to do too much to set it up.
34:35 You don't have to anticipate everything that's going to happen to it.
34:38 You just create one, and if people think there's a function there, hey, guess what?
34:43 All of a sudden, there's a function there.
34:45 The only part where it gets tricky is where you have to make sure the function returns something so you don't get like, you know, none attribute doesn't have whatever type of errors.
34:53 Yeah.
34:54 Yeah.
34:54 It's really powerful, the mock class, but that also sometimes makes it dangerous to use, since you can really just call in everything on it.
35:04 And yeah, there's also some problems with it, but I guess we can talk about that separately.
35:10 Yeah, absolutely.
35:11 One of the challenges, I think, is, let's say you've got some kind of database class, and you're going to make calls on it.
35:19 It would be easy to create a mock and say, here's the mock database.
35:22 You call stuff on it.
35:24 It's just going to kind of go along with that.
35:26 The challenge is, how do you provide that through, right?
35:29 You know, I was talking about that crazy system that everything is passing every dependency everywhere abstractly, right?
35:36 In this world, you've got to find a way to get the mock down inside the system so that it'll use it in the right place.
35:42 Yeah.
35:43 And you have to configure it exactly like you want it to behave.
35:46 Right.
35:47 Right.
35:47 If they call this with these parameters, return this value, right?
35:51 Yeah, since that's also something I stumbled across in the beginning.
35:55 So let's say you create a mock object that mocks the JSON library.
35:59 So you would just have JSON equals mock, where mock is the class.
36:04 And then you could just call JSON.dumps and give it any kind of argument you want to.