WEBVTT

00:00:00.001 --> 00:00:03.360
We know our tests should be relatively independent from other parts of the system.

00:00:03.360 --> 00:00:09.360
For example, running a test shouldn't generally call a credit card processing API and talk to a database

00:00:09.360 --> 00:00:12.800
when our goal is just to test the argument validation.

00:00:12.800 --> 00:00:17.860
And yet, your method that you want to test, it does all three of those things and more.

00:00:17.860 --> 00:00:18.760
What do you do?

00:00:18.760 --> 00:00:23.300
Some languages use elaborate dependency passing mechanisms and frameworks

00:00:23.300 --> 00:00:26.880
that go under the banner of inversion of control and dependency injection.

00:00:27.380 --> 00:00:33.320
In Python, we do sometimes have that, but it's much more common to just temporarily redefine

00:00:33.320 --> 00:00:36.780
what those two functions do using patching and mocking.

00:00:36.780 --> 00:00:42.180
On this episode, we welcome back Annalena Popkas to talk us through the whole spectrum of

00:00:42.180 --> 00:00:44.260
test doubles, dummies, mocks, and more.

00:00:44.260 --> 00:00:50.180
This is Talk Python To Me, episode 287, recorded August 24th, 2020.

00:00:50.180 --> 00:01:08.240
Welcome to Talk Python To Me, a weekly podcast on Python, the language, the libraries, the

00:01:08.240 --> 00:01:09.700
ecosystem, and the personalities.

00:01:09.700 --> 00:01:11.640
This is your host, Michael Kennedy.

00:01:11.640 --> 00:01:13.780
Follow me on Twitter, where I'm @mkennedy.

00:01:13.780 --> 00:01:17.540
Keep up with the show and listen to past episodes at talkpython.fm.

00:01:17.540 --> 00:01:20.040
And follow the show on Twitter via at talkpython.

00:01:20.040 --> 00:01:23.880
This episode is brought to you by Linode and monday.com.

00:01:23.880 --> 00:01:25.880
Please check out what they're offering during their segments.

00:01:25.880 --> 00:01:27.260
It really helps support the show.

00:01:28.700 --> 00:01:32.920
Do you want to learn Python, but you can't bear to subscribe to yet another service?

00:01:32.920 --> 00:01:36.180
At Talk Python Training, we hate subscriptions too.

00:01:36.180 --> 00:01:40.700
That's why our course bundle gives you full access to the entire library of courses for

00:01:40.700 --> 00:01:41.740
one fair price.

00:01:41.740 --> 00:01:42.860
That's right.

00:01:42.860 --> 00:01:47.620
With the course bundle, you save 70% off the full price of our courses, and you own them

00:01:47.620 --> 00:01:48.800
all forever.

00:01:48.800 --> 00:01:53.500
That includes courses published at the time of the purchase, as well as courses released

00:01:53.500 --> 00:01:54.920
within about a year of the bundle.

00:01:54.920 --> 00:02:00.420
So stop subscribing and start learning at talkpython.fm/everything.

00:02:00.420 --> 00:02:03.500
Anna Lena, welcome back to Talk Python To Me.

00:02:03.500 --> 00:02:04.140
Thanks.

00:02:04.140 --> 00:02:05.100
It's great to be back.

00:02:05.100 --> 00:02:06.920
Yeah, it's super to have you back.

00:02:06.920 --> 00:02:13.320
Last time we spoke about 100 days of code and Harry Potter and things like that, if I recall

00:02:13.320 --> 00:02:13.680
correctly.

00:02:13.680 --> 00:02:14.140
Is that right?

00:02:14.140 --> 00:02:15.620
Yes, that's correct.

00:02:16.000 --> 00:02:17.040
Yeah, that was really fun.

00:02:17.040 --> 00:02:21.260
And that was right at the height of the 100 days of code when everyone was really using

00:02:21.260 --> 00:02:22.160
that to learn to code.

00:02:22.160 --> 00:02:27.400
And so you had this unusual, but I think really engaging way of taking code and making it not

00:02:27.400 --> 00:02:31.860
just silly technical stuff, but making it this fun Harry Potter adventure world.

00:02:31.860 --> 00:02:33.580
Yeah, I still love that approach.

00:02:33.580 --> 00:02:38.780
So I always try to find something I'm passionate about and then trying to use it to learn.

00:02:39.160 --> 00:02:40.060
Yeah, excellent.

00:02:40.060 --> 00:02:46.220
So now we're going to come back and talk about writing code that we're more likely to be

00:02:46.220 --> 00:02:49.340
sure that works, testing code and using mocking and all that.

00:02:49.340 --> 00:02:55.520
But when we spoke last time, you were a, was it an internship at Microsoft?

00:02:55.520 --> 00:02:56.300
What kind of?

00:02:56.300 --> 00:02:57.680
It's something in between.

00:02:57.680 --> 00:03:02.000
It was called an AI residency at Microsoft Research in Cambridge in the UK.

00:03:02.000 --> 00:03:07.100
So it's like an intensive one year program where you learn a lot about how to apply machine

00:03:07.100 --> 00:03:09.540
learning, how to become a great research engineer.

00:03:09.540 --> 00:03:10.340
So cool.

00:03:10.340 --> 00:03:16.120
It's like, yeah, it's more than an internship, like a really long extended internship.

00:03:16.120 --> 00:03:19.920
I'm sure that was a really fun project experience.

00:03:19.920 --> 00:03:21.060
Oh yeah, it was amazing.

00:03:21.060 --> 00:03:25.260
Also the place Microsoft Research in Cambridge is just great.

00:03:25.260 --> 00:03:26.300
I really loved it there.

00:03:26.300 --> 00:03:28.460
Yeah, I can imagine.

00:03:28.460 --> 00:03:30.440
And how about now?

00:03:30.440 --> 00:03:31.500
What are you up to now?

00:03:31.500 --> 00:03:35.920
Yeah, so I finished the residency and I moved back to Germany and joined a German company

00:03:35.920 --> 00:03:36.820
called InnoVex.

00:03:36.820 --> 00:03:38.300
I also like it here a lot.

00:03:38.300 --> 00:03:43.760
And I'm working as a machine learning engineer, similar to what I did at Microsoft Research,

00:03:43.760 --> 00:03:46.000
but not so research heavy.

00:03:46.000 --> 00:03:50.020
So I'm doing more production code or production work.

00:03:50.020 --> 00:03:53.120
And I'm currently working in a pure data engineering project.

00:03:53.120 --> 00:03:57.760
So I've been learning a lot more about the work that comes before actually applying the machine

00:03:57.760 --> 00:04:00.280
learning algorithms, which is also very interesting.

00:04:00.280 --> 00:04:00.780
Yeah.

00:04:00.860 --> 00:04:04.980
So I would guess that involves a lot of pandas, a lot of cleaning up data, like getting stuff

00:04:04.980 --> 00:04:05.920
in the right format.

00:04:05.920 --> 00:04:07.000
Yes.

00:04:07.000 --> 00:04:07.520
Yeah.

00:04:07.780 --> 00:04:12.780
And then we give the data to the data scientists, which can just use the clean data to do their

00:04:12.780 --> 00:04:14.020
nice machine learning stuff.

00:04:14.020 --> 00:04:16.420
Yeah, you make them look good.

00:04:16.420 --> 00:04:18.840
You're like, oh, here, you just feed this over and it works great.

00:04:18.840 --> 00:04:20.400
Like it didn't start out that way.

00:04:21.200 --> 00:04:23.700
What kind of problems are you trying to solve or answer?

00:04:23.700 --> 00:04:26.220
It really depends on what the customer wants.

00:04:26.220 --> 00:04:32.940
So it can go from supply chain management and apply machine learning there to right now in

00:04:32.940 --> 00:04:38.780
the cloud, where we just create kind of a data lake in the Google cloud, where we have different

00:04:38.780 --> 00:04:44.620
data sources that have to be processed and brought together and all the other stuff.

00:04:44.740 --> 00:04:46.300
So there's just a lot going on.

00:04:46.300 --> 00:04:49.280
It's a very huge project with several teams working on it.

00:04:49.280 --> 00:04:49.860
Wow.

00:04:49.860 --> 00:04:50.460
Yeah.

00:04:50.460 --> 00:04:51.360
It sounds really fun.

00:04:51.360 --> 00:04:55.560
And it sounds like one of these big data projects that people talk about a lot, but not

00:04:55.560 --> 00:04:56.920
that many people actually do.

00:04:56.920 --> 00:04:57.320
Yeah.

00:04:57.320 --> 00:05:00.160
And it's also very interesting for me to see this other side.

00:05:00.280 --> 00:05:04.500
I've been working on machine learning for most of my computer science life.

00:05:04.500 --> 00:05:08.740
So seeing something different is also always very nice.

00:05:08.740 --> 00:05:09.640
Yeah, absolutely.

00:05:09.640 --> 00:05:12.820
And you also have some project going on in your spare time, yeah?

00:05:12.820 --> 00:05:13.940
Yes, exactly.

00:05:13.940 --> 00:05:15.660
So Kai Macht Schule.

00:05:15.660 --> 00:05:19.760
Yeah, it's I think like it's a German project.

00:05:19.760 --> 00:05:21.480
I'm doing voluntary work there.

00:05:21.480 --> 00:05:22.820
It's called Kai Macht Schule.

00:05:22.820 --> 00:05:26.960
That's like, I think you could translate it as AI goes to school.

00:05:27.060 --> 00:05:31.200
Yeah, where we teach AI and machine learning skills to kids in German schools.

00:05:31.200 --> 00:05:37.420
So we do classes usually on site, but now online due to the COVID crisis.

00:05:37.420 --> 00:05:43.580
And yeah, it was somewhat similar to what you talked about in the last episode or some recent

00:05:43.580 --> 00:05:45.640
episode with Nick Winter on Code Combat.

00:05:45.640 --> 00:05:49.100
Yeah, Code Combat is really a fun thing for kids as well.

00:05:49.100 --> 00:05:51.180
I think that's super neat what they're doing.

00:05:51.180 --> 00:05:55.380
I want to try it as well, even if I know how to write code in Python.

00:05:55.380 --> 00:05:56.920
It sounded so much fun.

00:05:56.920 --> 00:05:58.800
Yeah, it's really neat.

00:05:58.800 --> 00:06:03.220
I really enjoyed just kind of poking around with it and seeing it's, again, kind of like

00:06:03.220 --> 00:06:04.140
your Harry Potter world.

00:06:04.140 --> 00:06:08.940
It's a very different way to present programming to kids where you still type.

00:06:08.940 --> 00:06:11.820
It doesn't feel like the burden of being exactly right.

00:06:11.820 --> 00:06:15.120
You can kind of type it wrong and it'll mostly correct it for you.

00:06:15.120 --> 00:06:16.060
So it's pretty interesting.

00:06:16.060 --> 00:06:21.000
So with this project, you're teaching kids AI and machine learning.

00:06:21.400 --> 00:06:22.500
What does that even look like?

00:06:22.500 --> 00:06:24.300
What kind of stuff are you teaching them?

00:06:24.300 --> 00:06:27.000
What do they get when they're building little libraries and so on?

00:06:27.000 --> 00:06:27.400
Yeah.

00:06:27.400 --> 00:06:29.220
So we try different approaches.

00:06:29.220 --> 00:06:31.080
We always have a bit of theory.

00:06:31.080 --> 00:06:33.700
So what is AI?

00:06:33.700 --> 00:06:34.800
How does it work?

00:06:34.880 --> 00:06:39.220
We also have a part on the ethics behind AI, which I think is really important.

00:06:39.220 --> 00:06:43.840
And there's also some practical exercises with Jupyter Notebooks.

00:06:43.840 --> 00:06:49.900
Before we used an approach was where you have these blocks of programming parts, which you

00:06:49.900 --> 00:06:52.520
can stick together, like the for loops and so on.

00:06:52.600 --> 00:06:54.260
But we didn't like that so much.

00:06:54.260 --> 00:06:57.100
So right now we are using Jupyter Notebooks.

00:06:57.100 --> 00:07:01.500
And I think it's amazing since right now there's one, it's called KI Camp.

00:07:01.500 --> 00:07:02.860
It's like a four-day course.

00:07:02.860 --> 00:07:06.260
And the youngest one is in fifth grade.

00:07:06.260 --> 00:07:08.340
So it's like 11 or 12.

00:07:08.340 --> 00:07:10.560
And the oldest one is just about to graduate.

00:07:10.560 --> 00:07:14.520
And it's so nice to see these kids fascinated by this topic.

00:07:14.520 --> 00:07:15.200
Yeah.

00:07:15.200 --> 00:07:19.380
It's definitely going to give them a leg up, learn these types of things early and know

00:07:19.380 --> 00:07:23.240
about them and just to learn about Jupyter and computational thinking at all.

00:07:23.240 --> 00:07:23.780
Yeah.

00:07:23.780 --> 00:07:28.900
And Germany is also really not so good with the computer science work in school.

00:07:28.900 --> 00:07:34.140
I think in the US you are much better with teaching kids how to code in school already.

00:07:34.140 --> 00:07:41.980
For German kids, it's really hard to get to know AI or to find somewhat a way to get familiar

00:07:41.980 --> 00:07:47.560
with the topic without going out there and looking for yourself what's out on the internet.

00:07:48.080 --> 00:07:48.200
Yeah.

00:07:48.200 --> 00:07:51.040
There's the small percentage of kids who will do that.

00:07:51.040 --> 00:07:51.980
They'll go find it themselves.

00:07:51.980 --> 00:07:56.140
But the majority don't even know they would be interested until they get exposed to it.

00:07:56.140 --> 00:07:56.640
Exactly.

00:07:56.640 --> 00:07:57.140
Yeah.

00:07:57.140 --> 00:07:58.280
It was the same for me.

00:07:58.280 --> 00:08:01.080
So that's why I'm really passionate about this project.

00:08:01.080 --> 00:08:01.660
Yeah.

00:08:01.660 --> 00:08:02.080
Awesome.

00:08:02.080 --> 00:08:04.980
And you've definitely taken it quite far what you're doing these days.

00:08:04.980 --> 00:08:06.300
That's definitely the pinnacle.

00:08:06.300 --> 00:08:06.720
It's great.

00:08:06.720 --> 00:08:07.400
All right.

00:08:07.400 --> 00:08:12.180
Well, let's focus on our main topic for a little while on mocking.

00:08:12.180 --> 00:08:14.060
So how'd you get interested in it?

00:08:14.060 --> 00:08:14.880
How'd you get started?

00:08:14.920 --> 00:08:15.440
Yeah.

00:08:15.440 --> 00:08:20.100
So I stumbled upon this topic a few months back when I started working in this data engineering

00:08:20.100 --> 00:08:21.840
project I was just talking about.

00:08:21.840 --> 00:08:24.140
And we have lots of production code there.

00:08:24.140 --> 00:08:26.460
And I never heard of mocking before.

00:08:26.460 --> 00:08:28.540
So it was the first time I used it.

00:08:28.540 --> 00:08:32.480
And since then, I've been using it in almost all of the tests I write.

00:08:32.480 --> 00:08:34.720
It's a very controversial topic.

00:08:34.720 --> 00:08:39.660
So I watched quite a few PyCon talks on it and read quite a few blog posts.

00:08:39.660 --> 00:08:45.000
And yeah, it's just a big but very interesting thing to talk about.

00:08:45.000 --> 00:08:45.580
Yeah.

00:08:45.580 --> 00:08:50.540
So I think one of the controversies has to do with you can write your code in certain ways

00:08:50.540 --> 00:08:53.400
so it's more easy to test or it's harder to test.

00:08:53.900 --> 00:09:00.340
And some people see mocking as kind of covering over the bad code you've written or something

00:09:00.340 --> 00:09:01.280
to that effect, right?

00:09:01.280 --> 00:09:03.380
Hopefully that sort of summarizes it.

00:09:03.380 --> 00:09:04.340
Yeah, exactly.

00:09:04.340 --> 00:09:06.260
And I completely understand that.

00:09:06.260 --> 00:09:10.920
So you shouldn't use mocking to fix your badly written code.

00:09:10.920 --> 00:09:14.500
So you, of course, you should first think about, is my code good?

00:09:14.500 --> 00:09:15.880
Do I want to refactor it?

00:09:16.580 --> 00:09:20.080
Are there changes I can make to make it easier to test?

00:09:20.080 --> 00:09:23.100
But sometimes it can be a really good tool.

00:09:23.100 --> 00:09:24.380
I think it's a great tool.

00:09:24.380 --> 00:09:28.380
I think when it's used in the right ways and right places, it's just what you need.

00:09:28.380 --> 00:09:29.380
Yes, I agree.

00:09:29.380 --> 00:09:29.720
Yeah.

00:09:29.720 --> 00:09:34.260
I mean, Python is so much about the sort of practicality beats purity.

00:09:34.260 --> 00:09:36.580
You know, it's part of the Zen of Python and all that.

00:09:36.580 --> 00:09:41.000
And it's just, let's just do what we need to do to make stuff work.

00:09:41.000 --> 00:09:45.980
And I think one of the examples where this is really different from other languages is in

00:09:45.980 --> 00:09:49.500
Python, we don't have things like protected variables.

00:09:49.500 --> 00:09:53.200
We don't have as often like concrete interfaces.

00:09:53.200 --> 00:09:55.720
We don't have type enforcement, right?

00:09:55.720 --> 00:09:58.420
Like the thing you passed here must be this interface.

00:09:58.420 --> 00:10:00.160
And if it's not, we're going to raise an exception.

00:10:00.160 --> 00:10:04.200
We have type hints, but that's like an editor or like tool helper.

00:10:04.200 --> 00:10:08.100
It doesn't mean that runtime it's not going to work or it won't compile or whatever.

00:10:08.100 --> 00:10:08.660
Yeah.

00:10:08.660 --> 00:10:09.060
Right.

00:10:09.060 --> 00:10:15.380
And so I feel like mocking and patching is like, it's sort of, it's more embraced in this

00:10:15.380 --> 00:10:19.240
world where it's like, look, if we just do this little thing, we can avoid all this complexity

00:10:19.240 --> 00:10:24.460
and all of these design patterns and all of this stuff that technically would be maybe a

00:10:24.460 --> 00:10:27.040
more official, pure computer sciencey way.

00:10:27.040 --> 00:10:31.320
But if you look at the stuff that gets built from it, it gets really hard to deal with it

00:10:31.320 --> 00:10:31.660
and ugly.

00:10:31.660 --> 00:10:32.220
Yeah.

00:10:32.220 --> 00:10:33.140
Yeah.

00:10:33.140 --> 00:10:33.520
I agree.

00:10:33.860 --> 00:10:34.060
Yeah.

00:10:34.060 --> 00:10:39.120
I remember I worked on this one project and it was originally written, I think in Java

00:10:39.120 --> 00:10:40.680
and then converted to C#.

00:10:40.680 --> 00:10:44.600
And it used, I think every design pattern that you could possibly name.

00:10:44.600 --> 00:10:49.720
And it used every single thing that used some sort of dependency.

00:10:49.720 --> 00:10:51.520
It had an interface for that dependency.

00:10:51.520 --> 00:10:53.580
It would pass that in into the constructor.

00:10:53.580 --> 00:10:56.740
And then when it created objects, it would pass that further down.

00:10:56.740 --> 00:11:01.600
And what you ended up with was the entire code that you wrote was all this abstract stuff.

00:11:01.600 --> 00:11:06.340
And you would look at it like, well, I see all the functions, but I just don't even know

00:11:06.340 --> 00:11:09.880
where I would go to find out what actually does this.

00:11:09.880 --> 00:11:12.980
It's just, it was so insanely complicated.

00:11:12.980 --> 00:11:17.820
So I've seen that far in and I've seen the world where people just go, you know, okay, we're

00:11:17.820 --> 00:11:21.840
not going to set up all those structures, but we're just going to do a patch like deep down

00:11:21.840 --> 00:11:23.200
inside of some function call.

00:11:23.200 --> 00:11:27.240
And if I had to pick one of those two worlds, I would definitely live in the world where

00:11:27.240 --> 00:11:31.840
we just keep things simple as it's, it was not fun to work on that project in that way.

00:11:31.840 --> 00:11:33.060
It sounds terrible.

00:11:33.060 --> 00:11:33.780
Yeah.

00:11:33.780 --> 00:11:34.020
Yeah.

00:11:34.020 --> 00:11:36.180
It was like a, probably a six month project.

00:11:36.180 --> 00:11:38.900
I'm just like, I'm constantly frustrated on this project.

00:11:38.900 --> 00:11:42.280
So let's, I guess, start at the beginning.

00:11:42.280 --> 00:11:44.240
Like what is mocking?

00:11:44.240 --> 00:11:48.900
There's a lot of folks who listen, who come from a sort of scientific background where they

00:11:48.900 --> 00:11:51.100
haven't done official computer science or they're self-taught.

00:11:51.180 --> 00:11:52.940
Maybe, maybe this idea is new to them.

00:11:52.940 --> 00:11:53.800
What is, what's mocking?

00:11:53.800 --> 00:11:54.300
Yeah.

00:11:54.300 --> 00:11:58.380
So a mock simulates the existence and behavior of a real object.

00:11:58.380 --> 00:12:04.820
I guess we can go over a few examples, but if you use mocking, you as a developer can

00:12:04.820 --> 00:12:08.640
improve the quality of your tests and also test code in a controlled environment.

00:12:08.640 --> 00:12:13.680
And it's especially useful if you have external dependencies, like if you want to write to a

00:12:13.680 --> 00:12:15.720
database or do stuff like that.

00:12:15.720 --> 00:12:21.340
And there's a nice Python library, which is included in unit test, which is called unit

00:12:21.340 --> 00:12:23.600
test.mock, which can be used for mocking.

00:12:23.600 --> 00:12:27.600
I think there are also some more specialized libraries out there.

00:12:27.600 --> 00:12:31.940
I think there's one, especially for mocking date time, but I've never used it.

00:12:32.060 --> 00:12:34.600
So I'm only using unit test.mock.

00:12:34.600 --> 00:12:35.320
Yes.

00:12:35.320 --> 00:12:38.900
I think the one out there called that is called freeze gun.

00:12:38.900 --> 00:12:40.140
Yes, exactly.

00:12:40.140 --> 00:12:40.440
Yeah.

00:12:40.440 --> 00:12:40.940
That's it.

00:12:40.940 --> 00:12:41.540
Yes.

00:12:41.540 --> 00:12:42.340
A freeze gun.

00:12:42.820 --> 00:12:48.760
And that one basically, you know, like you said, allows you to control the date time module.

00:12:48.760 --> 00:12:52.480
So there's obvious dependencies that you would think of.

00:12:52.480 --> 00:12:58.640
Like if I have a traditional web application, maybe it calls some API, like my online courses

00:12:58.640 --> 00:12:58.880
thing.

00:12:58.880 --> 00:13:00.160
It's going to call Stripe.

00:13:00.160 --> 00:13:03.920
It's probably going to call MailChimp APIs, does some other stuff.

00:13:03.920 --> 00:13:05.220
It's going to talk to a database.

00:13:05.360 --> 00:13:09.340
So when you think about dependencies, you think, okay, database, maybe the file system,

00:13:09.340 --> 00:13:13.720
external APIs, and those are all things you can mock and you probably want to.

00:13:13.720 --> 00:13:18.720
But when I first got into this world, one of the things that really surprised me was how

00:13:18.720 --> 00:13:20.240
hard it is to work with time.

00:13:20.240 --> 00:13:26.320
If I want to say, I would like to call this thing before, like, let's just say it's e-commerce.

00:13:26.320 --> 00:13:29.980
Like I want to make sure that this discount code is not expired now.

00:13:29.980 --> 00:13:32.820
So it gives me the discount, but in a week it will be expired.

00:13:32.820 --> 00:13:34.940
You know, like that's really hard to deal with.

00:13:34.940 --> 00:13:35.180
Right.

00:13:35.180 --> 00:13:35.660
Yeah.

00:13:35.660 --> 00:13:40.120
I think that's a very good place to use mocking for like, it's a great example for that,

00:13:40.120 --> 00:13:41.580
where it can be really useful.

00:13:41.580 --> 00:13:42.100
Yeah.

00:13:42.100 --> 00:13:46.280
And the alternative, I talked about this dystopian world that I lived in for a while.

00:13:46.280 --> 00:13:52.780
The alternative would be, you would have to create a fake class that read, like that you

00:13:52.780 --> 00:13:55.100
used to get what now is, right?

00:13:55.100 --> 00:14:01.140
Instead of just saying datetime.now, you have to create a class like time provider now, and

00:14:01.140 --> 00:14:05.120
then everybody has to agree to not use datetime.now, but they'll have to share

00:14:05.120 --> 00:14:07.000
this other thing that you're going to pass around.

00:14:07.000 --> 00:14:08.600
And that's just, that's just crazy.

00:14:08.600 --> 00:14:08.900
Right.

00:14:08.900 --> 00:14:10.120
Like it makes no sense.

00:14:10.120 --> 00:14:10.340
Yeah.

00:14:10.340 --> 00:14:11.840
It's unnecessarily complicated.

00:14:11.840 --> 00:14:12.640
Yeah.

00:14:12.640 --> 00:14:14.200
It's just so complicated.

00:14:14.640 --> 00:14:18.020
And so you can, if you just mock out what now means.

00:14:18.020 --> 00:14:18.440
That's it.

00:14:18.440 --> 00:14:18.760
Yeah.

00:14:18.760 --> 00:14:19.400
Then you're good.

00:14:19.400 --> 00:14:20.120
It's fixed.

00:14:20.120 --> 00:14:20.400
Right.

00:14:20.400 --> 00:14:22.000
So yeah, it's pretty cool.

00:14:22.000 --> 00:14:23.800
And Freezegun is one of the libraries.

00:14:23.800 --> 00:14:27.780
I'm sure there's a bunch out there, but that's a cool one for doing this kind of stuff with

00:14:27.780 --> 00:14:28.820
specifically with time.

00:14:30.440 --> 00:14:33.180
This portion of Talk Python To Me is brought to you by Linode.

00:14:33.180 --> 00:14:37.300
Whether you're working on a personal project or managing your enterprise's infrastructure,

00:14:37.300 --> 00:14:41.860
Linode has the pricing, support, and scale that you need to take your project to the next

00:14:41.860 --> 00:14:42.140
level.

00:14:42.140 --> 00:14:47.860
With 11 data centers worldwide, including their newest data center in Sydney, Australia, enterprise

00:14:47.860 --> 00:14:54.040
grade hardware, S3 compatible storage, and the next generation network, Linode delivers the

00:14:54.040 --> 00:14:56.800
performance that you expect at a price that you don't.

00:14:56.800 --> 00:15:02.720
Get started on Linode today with a $20 credit and you get access to native SSD storage, a 40

00:15:02.720 --> 00:15:08.360
gigabit network, industry leading processors, their revamped cloud manager at cloud.linode.com,

00:15:08.360 --> 00:15:12.840
root access to your server, along with their newest API and a Python CLI.

00:15:12.840 --> 00:15:18.940
Just visit talkpython.fm/Linode when creating a new Linode account and you'll automatically

00:15:18.940 --> 00:15:20.880
get $20 credit for your next project.

00:15:20.880 --> 00:15:22.160
Oh, and one last thing.

00:15:22.160 --> 00:15:22.940
They're hiring.

00:15:22.940 --> 00:15:26.040
Go to linode.com slash careers to find out more.

00:15:26.040 --> 00:15:27.380
Let them know that we sent you.

00:15:27.380 --> 00:15:31.760
So you talked about replacing dependencies.

00:15:31.760 --> 00:15:34.140
I guess give us some more examples.

00:15:34.140 --> 00:15:37.760
Time is one that maybe doesn't first come up, but what are some of the type of dependencies

00:15:37.760 --> 00:15:39.000
you all were working with?

00:15:39.000 --> 00:15:41.660
So I've been working a lot with the Google Cloud client.

00:15:42.340 --> 00:15:46.560
So where you want to write or either you want to communicate with the Google Cloud with

00:15:46.560 --> 00:15:52.860
different services there, or you want to write to the storage and you need to someone, you

00:15:52.860 --> 00:15:55.520
have a client and you want to communicate with the Google Cloud.

00:15:55.520 --> 00:15:59.240
And that's the part where we mostly use mocking.

00:15:59.240 --> 00:16:05.480
So to somewhat make sure that we test that the file is written, or at least that we have

00:16:05.480 --> 00:16:10.640
the correct paths, the correct function call, but we don't actually want to write the file

00:16:10.640 --> 00:16:13.740
to the Google Cloud every time or remove it.

00:16:13.740 --> 00:16:14.200
Right.

00:16:14.200 --> 00:16:20.120
You know, cloud computing, I think it has a really interesting challenge around testing.

00:16:20.120 --> 00:16:22.020
It just, in a lot of ways, right?

00:16:22.020 --> 00:16:26.360
Like you don't, if you're going to work with the API, you obviously have to not talk to the

00:16:26.360 --> 00:16:26.860
real API.

00:16:26.860 --> 00:16:31.420
You don't really want to create a virtual machine or a Kubernetes node or whatever, but you do

00:16:31.420 --> 00:16:32.960
want to test that that code's going to work.

00:16:33.080 --> 00:16:37.940
But at the same time, a lot of times the tests depend on something meaningful coming back.

00:16:37.940 --> 00:16:38.400
Yeah.

00:16:38.400 --> 00:16:38.960
Right.

00:16:38.960 --> 00:16:43.100
There's so much going on in the cloud side that I think it's pretty tricky.

00:16:43.100 --> 00:16:44.720
Do you guys do anything special there?

00:16:44.720 --> 00:16:49.660
Like I know in AWS, there's like a fake local AWS type thing you can run.

00:16:49.660 --> 00:16:53.740
And I know I've talked about it a while ago and I forgot what it's called, but do you guys

00:16:53.740 --> 00:16:54.500
do anything like that?

00:16:54.500 --> 00:16:55.760
Not at the moment.

00:16:55.760 --> 00:17:00.060
I think someone is working on finding ways to improve this since we are using mocking

00:17:00.060 --> 00:17:06.340
quite a lot, but it's a really complicated and complex thing since we have a huge code base

00:17:06.340 --> 00:17:08.840
already and you would have to change all the code again.

00:17:08.840 --> 00:17:14.240
So doing kind of refactoring at this point is always a big deal.

00:17:14.240 --> 00:17:16.280
But right now we are just...

00:17:16.280 --> 00:17:17.600
Yeah, it might not even be worth it.

00:17:17.600 --> 00:17:17.780
Yeah.

00:17:17.780 --> 00:17:18.340
Yeah.

00:17:18.340 --> 00:17:19.220
Yeah, exactly.

00:17:19.220 --> 00:17:19.780
Yeah.

00:17:19.780 --> 00:17:22.240
And I think there's also something to be said for that, right?

00:17:22.240 --> 00:17:27.360
Like sometimes it's like we could create a mock or fake or we'll talk about the different

00:17:27.360 --> 00:17:28.940
terminologies here in a minute.

00:17:28.940 --> 00:17:29.280
Yeah.

00:17:29.280 --> 00:17:31.580
But sometimes it's like, you know what?

00:17:31.580 --> 00:17:33.340
I'm just going to let it ride to the file system.

00:17:33.340 --> 00:17:34.560
It's not the end of the world.

00:17:34.560 --> 00:17:35.800
We're going to keep going.

00:17:35.800 --> 00:17:41.160
One of the really tricky ones I think has to do with data access, right?

00:17:41.160 --> 00:17:44.820
I'm going to go talk to the database and get this and then I need to get this other thing

00:17:44.820 --> 00:17:45.900
that's related to that.

00:17:45.900 --> 00:17:50.760
And I think it's a constant challenge to figure out how much of that you replace and how much

00:17:50.760 --> 00:17:54.000
of it you just test against the database or test against a file or something.

00:17:54.000 --> 00:17:54.560
Yeah.

00:17:54.560 --> 00:17:56.980
It's sometimes difficult to find the right way.

00:17:56.980 --> 00:18:01.320
Also, if you are working in a team and other like different people have different opinions

00:18:01.320 --> 00:18:05.240
and like different things, but there's also a middle ground somewhere.

00:18:05.240 --> 00:18:06.300
Yeah, for sure.

00:18:06.300 --> 00:18:06.940
Yeah.

00:18:06.940 --> 00:18:11.360
I could see one person on the team is all about like we have to do it the right way where there's

00:18:11.360 --> 00:18:12.280
no external dependencies.

00:18:12.280 --> 00:18:14.900
And the other person's like, we also have to get stuff done.

00:18:14.900 --> 00:18:16.280
You know, I also have to.

00:18:16.280 --> 00:18:20.740
I can't spend all my time recreating all of these systems that you're trying to talk

00:18:20.740 --> 00:18:25.160
to in ways that are sufficiently accurate so that when you call them, the test data comes

00:18:25.160 --> 00:18:30.080
back, but it's as accurate or realistic enough that you're really getting a meaningful test.

00:18:30.080 --> 00:18:31.280
So it's tricky.

00:18:31.740 --> 00:18:36.960
So you have a example class speaking of Harry Potter and all that.

00:18:36.960 --> 00:18:37.520
Yes.

00:18:37.520 --> 00:18:38.740
That we're going to use.

00:18:38.740 --> 00:18:40.120
We're going to kind of build up some ideas.

00:18:40.120 --> 00:18:42.940
And it's always hard to talk about code in audio format.

00:18:42.940 --> 00:18:44.180
So we'll keep it simple.

00:18:44.180 --> 00:18:46.780
But maybe just give us a quick introduction.

00:18:46.780 --> 00:18:47.320
Yeah.

00:18:47.320 --> 00:18:52.840
So we have very simple spell class, which where you have just the constructor in the beginning.

00:18:53.120 --> 00:18:54.860
And a spell has, of course, a name.

00:18:54.860 --> 00:18:57.160
It has an incantation and a description.

00:18:57.160 --> 00:19:05.700
So for example, I think there's Accio in Harry Potter, where it moves an object towards the

00:19:05.700 --> 00:19:08.000
person who is casting the spell.

00:19:08.000 --> 00:19:11.420
And a description could be what I just said.

00:19:11.420 --> 00:19:12.580
And then you have the incantation.

00:19:12.580 --> 00:19:14.040
Yeah, moves object towards person.

00:19:14.040 --> 00:19:14.880
Yeah, exactly.

00:19:14.880 --> 00:19:15.260
Exactly.

00:19:15.260 --> 00:19:16.800
So that would be an example.

00:19:16.800 --> 00:19:17.980
Okay, cool.

00:19:17.980 --> 00:19:18.660
All right.

00:19:18.660 --> 00:19:21.760
So we'll build up on this as we go through these different ideas here.

00:19:21.760 --> 00:19:26.400
And we've been talking about mocking as if it's all kind of the same.

00:19:26.400 --> 00:19:32.360
But if you dig into it, there's actually like a spectrum of ways in which you can do mocking.

00:19:32.360 --> 00:19:38.380
One of those might be, I just, when I call this function, I want it to not write to the

00:19:38.380 --> 00:19:39.500
log on the file system.

00:19:39.500 --> 00:19:41.940
And it might be enough that it just doesn't do that.

00:19:41.940 --> 00:19:43.220
You don't care what it does.

00:19:43.220 --> 00:19:44.160
It just doesn't do that.

00:19:44.160 --> 00:19:48.740
On the other hand, there's like very advanced, tricky usage.

00:19:48.740 --> 00:19:54.820
Like when I call this function, I want to make sure that it checks whether the person is an admin.

00:19:54.820 --> 00:19:56.740
If I say yes, I want to do one thing.

00:19:56.740 --> 00:20:00.760
But I want to make sure that it actually always, always calls this function to make sure that it

00:20:00.760 --> 00:20:04.360
checked for them, even though you couldn't observe that as a side effect.

00:20:04.360 --> 00:20:08.580
I want to make sure that it's like calling this once and this twice or in this order.

00:20:08.580 --> 00:20:10.500
Like there's a lot of tricky things.

00:20:10.500 --> 00:20:12.440
And those feel like very different things.

00:20:12.440 --> 00:20:16.220
So in the mocking world, there's different names for these things, right?

00:20:16.220 --> 00:20:16.920
Yes.

00:20:16.920 --> 00:20:22.860
And there's also disagreement, I guess, about the terminology and also the definitions of

00:20:22.860 --> 00:20:25.900
these different kinds of mocking behaviors that you can distinguish.

00:20:25.900 --> 00:20:26.680
Yeah.

00:20:26.680 --> 00:20:28.760
And it may or may not be useful.

00:20:28.760 --> 00:20:33.460
Like people can decide how much they care about being very precise about calling it one thing

00:20:33.460 --> 00:20:33.920
or the other.

00:20:34.120 --> 00:20:40.180
But yeah, let's talk about it in the fine grained view, just so people get the full exposure

00:20:40.180 --> 00:20:43.220
and they can decide to ignore the differences if they want, right?

00:20:43.220 --> 00:20:45.020
Yes, I think that's a good idea.

00:20:45.020 --> 00:20:52.080
So yeah, I think the overall name or the name for these kinds of mocking behaviors is called

00:20:52.080 --> 00:20:52.720
test doubles.

00:20:52.720 --> 00:20:59.500
So there are the fine grained view objects, which are not real, can be either dummies,

00:20:59.500 --> 00:21:02.660
fakes, stubs, mocks, or spies.

00:21:02.660 --> 00:21:05.340
And all of these are so-called test doubles.

00:21:05.340 --> 00:21:05.900
Yeah.

00:21:05.900 --> 00:21:09.800
And as I just said, these definitions are also controversial.

00:21:09.800 --> 00:21:14.360
And there are sometimes so different sources describe them slightly differently.

00:21:14.360 --> 00:21:19.020
But I think it's still possible to get an idea of what they are about.

00:21:19.020 --> 00:21:19.540
Yeah.

00:21:19.540 --> 00:21:20.560
Yeah, absolutely.

00:21:20.560 --> 00:21:24.740
So let's start, I guess, at the simple side of things.

00:21:24.740 --> 00:21:29.420
I feel like this whole concept has a little bit of a I'm making fun of you thing.

00:21:29.420 --> 00:21:31.620
So mocking to like insult somebody.

00:21:31.620 --> 00:21:34.780
And then you've got dummies, you've got fakes.

00:21:34.780 --> 00:21:37.260
So let's start with the dummies.

00:21:37.260 --> 00:21:40.500
Yeah, I think the dummies are the easiest to understand.

00:21:40.500 --> 00:21:41.120
I agree.

00:21:41.120 --> 00:21:41.680
Yeah.

00:21:41.680 --> 00:21:46.040
And a dummy is just an object which is passed around, but never actually used.

00:21:46.040 --> 00:21:49.220
So a dummy is not intended to be used in your tests.

00:21:49.220 --> 00:21:52.440
And it does not have any effect on the behavior of the test.

00:21:52.440 --> 00:21:58.040
And an example would be when you have attributes that you need to instantiate a class,

00:21:58.040 --> 00:22:01.440
but you don't really care about what they are.

00:22:01.440 --> 00:22:06.680
For example, for the spell class, if you need a spell instance in your tests,

00:22:06.680 --> 00:22:08.700
but you don't care about the description,

00:22:08.700 --> 00:22:14.060
then you could just pause in an empty string or write whatever you want to in that string.

00:22:14.060 --> 00:22:15.280
And that would be then a dummy.

00:22:15.280 --> 00:22:15.720
Right.

00:22:15.720 --> 00:22:17.640
If you don't supply it, it's going to crash.

00:22:17.640 --> 00:22:18.280
Yes.

00:22:18.280 --> 00:22:21.160
But you don't actually ever use it or care about it.

00:22:21.160 --> 00:22:23.960
You just have to make it get out of the way and keep working.

00:22:23.960 --> 00:22:24.520
Yes.

00:22:24.520 --> 00:22:24.980
Yeah.

00:22:24.980 --> 00:22:25.660
Okay.

00:22:25.660 --> 00:22:26.720
So that's dummies.

00:22:27.100 --> 00:22:28.300
Next up is fakes.

00:22:28.300 --> 00:22:29.000
Yes.

00:22:29.000 --> 00:22:32.600
So a fake implements a fake version of a class or method.

00:22:32.600 --> 00:22:38.320
It has a working implementation, but it takes some kind of shortcut such that it's not suitable

00:22:38.320 --> 00:22:39.200
for production.

00:22:39.200 --> 00:22:42.280
And that could be in a memory database.

00:22:42.280 --> 00:22:46.980
So usually in production, you would have a database that you write your files to.

00:22:47.540 --> 00:22:53.340
But during testing, you could have some in-memory database that you only use during your tests.

00:22:53.340 --> 00:22:53.840
Yeah.

00:22:53.840 --> 00:22:54.900
That makes a lot of sense.

00:22:54.900 --> 00:22:58.840
And that's definitely one of the tricky things, I think, is databases.

00:22:58.840 --> 00:23:03.460
The other one that would be really tricky would be, say, an API call.

00:23:03.940 --> 00:23:08.720
Like, for example, one of the things I have to do in my code is I have to figure out where

00:23:08.720 --> 00:23:14.000
is this person located physically so that I can pick the right video server to deliver

00:23:14.000 --> 00:23:16.320
the fastest video to them.

00:23:16.320 --> 00:23:21.960
And so there's a call to go to the API that tells me where they are based on their IP address,

00:23:21.960 --> 00:23:23.680
like what country basically they're in.

00:23:23.680 --> 00:23:26.120
So I can work out what one to send, right?

00:23:26.120 --> 00:23:30.080
Every time I run a test, I don't want to call that API, right?

00:23:30.080 --> 00:23:30.460
Yeah.

00:23:30.460 --> 00:23:31.680
And I don't really...

00:23:31.680 --> 00:23:32.720
That's also a good example.

00:23:33.000 --> 00:23:33.240
Yeah.

00:23:33.240 --> 00:23:36.600
And I mean, probably the test doesn't actually care where it said they were.

00:23:36.600 --> 00:23:40.700
But it's, you know, it's going to have to have some kind of behavior because it's going

00:23:40.700 --> 00:23:42.800
to have to return a value so the program works.

00:23:42.800 --> 00:23:48.680
Like, so maybe I could come up with a mock or a fake specifically that says whenever they

00:23:48.680 --> 00:23:51.040
ask where they are, they're always in Kansas City.

00:23:51.040 --> 00:23:52.920
It doesn't matter where they really are.

00:23:52.920 --> 00:23:57.300
Just tell them it's in Kansas City so that something can happen where the thing keeps working,

00:23:57.300 --> 00:23:57.560
right?

00:23:57.560 --> 00:23:58.260
Yes.

00:23:58.260 --> 00:24:02.780
That's also somewhat a good introduction of the next one, Stubs.

00:24:02.780 --> 00:24:04.780
Stubs returns.

00:24:04.780 --> 00:24:07.680
It has some pre-programmed behavior.

00:24:07.680 --> 00:24:11.200
Most of the times they simply return fixed values or canned data.

00:24:11.880 --> 00:24:14.960
Like you just said, for example, always return Kansas City.

00:24:14.960 --> 00:24:18.520
And yeah, let's look at the spell class again.

00:24:18.520 --> 00:24:24.160
Maybe the spell class could have a method get similar spells, which searches some database

00:24:24.160 --> 00:24:27.040
and then you would get similar spells back.

00:24:27.780 --> 00:24:33.520
And this is, of course, quite complex since finding these similar spells will probably be very difficult.

00:24:33.520 --> 00:24:34.240
And you would.

00:24:34.240 --> 00:24:34.700
Right.

00:24:34.700 --> 00:24:40.380
Maybe the real version is running machine learning or some sort of crazy system.

00:24:40.600 --> 00:24:42.720
And you don't want that to happen all the time, right?

00:24:42.720 --> 00:24:43.160
Yes.

00:24:43.160 --> 00:24:45.940
Since it would probably slow down your whole testing.

00:24:45.940 --> 00:24:55.300
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.

00:24:55.600 --> 00:24:55.960
Yeah.

00:24:55.960 --> 00:24:56.540
Yeah.

00:24:56.540 --> 00:24:58.520
That seems like a really good example there.

00:24:58.520 --> 00:24:59.800
So I don't know.

00:24:59.800 --> 00:25:01.980
I do have a hard time knowing exactly.

00:25:01.980 --> 00:25:02.300
Okay.

00:25:02.300 --> 00:25:04.460
I've got this idea of which one does it fit into.

00:25:04.460 --> 00:25:09.940
It's almost like a spectrum saying that color is purple and that color is red.

00:25:10.600 --> 00:25:13.660
What is the color that's purple but sort of towards red?

00:25:13.660 --> 00:25:14.280
You know what I mean?

00:25:14.280 --> 00:25:15.880
Yeah.

00:25:15.880 --> 00:25:16.960
Yeah.

00:25:16.960 --> 00:25:17.260
Cool.

00:25:17.260 --> 00:25:17.560
All right.

00:25:17.560 --> 00:25:21.780
So making our way across this rainbow, I guess, we have mocks.

00:25:21.780 --> 00:25:22.520
Yeah.

00:25:22.520 --> 00:25:24.620
So mocks are closely related to stops.

00:25:24.620 --> 00:25:29.200
And there's this huge stack overflow post on the differences between mocks and stops.

00:25:29.200 --> 00:25:35.100
And there you can also get a bit of an idea of the controversy surrounding this topic.

00:25:35.100 --> 00:25:36.380
But yeah.

00:25:36.380 --> 00:25:36.680
Yeah.

00:25:36.680 --> 00:25:38.800
And I'll put that link in the show notes so people can find it.

00:25:38.800 --> 00:25:39.240
Yeah.

00:25:39.240 --> 00:25:39.960
That's a good idea.

00:25:40.480 --> 00:25:44.460
So a mock does not have predetermined behavior, which stops have.

00:25:44.460 --> 00:25:46.340
Instead, it has to be configured.

00:25:46.340 --> 00:25:52.360
So an important difference between mocks and stops is that a mock records which calls have

00:25:52.360 --> 00:25:53.080
been executed.

00:25:53.080 --> 00:25:56.720
So it can be used to verify not only the result.

00:25:56.720 --> 00:25:59.040
That's something that a stop can do too.

00:25:59.040 --> 00:26:05.200
But a mock can verify how the result was achieved so that the correct methods have been invoked

00:26:05.200 --> 00:26:06.260
on the mock object.

00:26:06.260 --> 00:26:06.860
Yeah.

00:26:06.860 --> 00:26:10.060
And this is where it starts to get complicated, I think.

00:26:10.360 --> 00:26:16.800
One of the ideas of just programming in general functions and classes, but also testing is

00:26:16.800 --> 00:26:24.100
you shouldn't depend upon the internal implementation of a thing when you're testing it or calling

00:26:24.100 --> 00:26:24.960
it from the outside.

00:26:25.100 --> 00:26:30.640
So if I have a thing that says register a new user, maybe I want to just check if I give

00:26:30.640 --> 00:26:32.880
it valid information, it gives me a new user.

00:26:32.880 --> 00:26:36.380
If I give it like a malformed email, it'll give me an exception, right?

00:26:36.380 --> 00:26:38.840
Like that would be totally straightforward.

00:26:38.840 --> 00:26:48.060
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.

00:26:48.060 --> 00:26:55.300
And then you're getting more and more tied to the internal details of what that piece is doing, which is fine, maybe.

00:26:55.440 --> 00:26:56.580
But then you change your code.

00:26:56.580 --> 00:26:58.040
And all of a sudden, all your tests break.

00:26:58.040 --> 00:27:01.880
You're like, well, now we got to go rewrite these tests because we don't have this thing that we were

00:27:01.880 --> 00:27:10.160
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.

00:27:10.160 --> 00:27:10.860
Yeah.

00:27:10.860 --> 00:27:11.460
Yeah.

00:27:11.460 --> 00:27:12.600
We had that problem, too.

00:27:12.600 --> 00:27:15.480
So, yeah, that's something you have to think about, too.

00:27:15.480 --> 00:27:18.020
But at the same time, there's good uses for this.

00:27:18.020 --> 00:27:27.900
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.

00:27:27.900 --> 00:27:32.300
And somebody forgets to check whether someone is permitted to go in there.

00:27:32.300 --> 00:27:34.800
That's really bad if that ever gets discovered.

00:27:34.800 --> 00:27:35.300
You know what I mean?

00:27:35.300 --> 00:27:40.540
Like, oh, did we forget to check in the show me all the users and their private information part?

00:27:40.540 --> 00:27:42.780
We forget to check if you're logged in.

00:27:42.780 --> 00:27:43.140
Whoops.

00:27:43.140 --> 00:27:45.980
You know, that kind of stuff could totally happen.

00:27:45.980 --> 00:27:52.500
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.

00:27:52.500 --> 00:27:53.080
Right.

00:27:53.080 --> 00:27:55.340
That function was called no matter what.

00:27:55.340 --> 00:27:55.660
Right.

00:27:55.660 --> 00:27:56.280
Yeah.

00:27:56.280 --> 00:27:56.560
Yeah.

00:27:56.560 --> 00:28:02.060
This portion of Talk Python To Me is sponsored by Monday.com.

00:28:02.060 --> 00:28:07.620
Monday.com is an online platform that powers over 100,000 teams daily work.

00:28:07.620 --> 00:28:15.140
It's an easy to use, flexible and visual teamwork platform beautifully designed to manage any team, organization or online process.

00:28:15.140 --> 00:28:20.360
Now, for most of us, we missed our chance to build the first apps ever in the mobile app stores.

00:28:20.360 --> 00:28:24.760
It was a once in a lifetime opportunity, but it's one that's coming around again.

00:28:25.220 --> 00:28:31.540
Monday.com is launching their marketplace and running a contest for the best new apps featured right from the get-go.

00:28:31.540 --> 00:28:35.080
Want to be one of the first in the Monday.com apps marketplace?

00:28:35.080 --> 00:28:36.560
Start building today.

00:28:36.560 --> 00:28:43.420
They're even giving away $184,000 in prizes, including three Teslas, 10 MacBooks and more.

00:28:43.420 --> 00:28:47.560
Build your idea for an app and get in front of hundreds of thousands of users on day one.

00:28:47.560 --> 00:28:53.900
Start building today by visiting Monday.com slash Python or just click the link in your podcast player's show notes.

00:28:56.180 --> 00:28:58.720
And so, these mocks, I think that's the thing you could do, right?

00:28:58.720 --> 00:29:02.800
You could say, like, expect that this was, what is it, assert called once or something like that, right?

00:29:03.060 --> 00:29:05.720
Yes, there are different kinds of assert calls there.

00:29:05.720 --> 00:29:06.060
Okay.

00:29:06.060 --> 00:29:07.980
We can talk about this later as well.

00:29:07.980 --> 00:29:09.780
So, there is assert called once.

00:29:09.780 --> 00:29:18.560
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.

00:29:18.560 --> 00:29:21.440
So, there are kind of different things you can do.

00:29:21.440 --> 00:29:22.940
And that can be very helpful.

00:29:22.940 --> 00:29:23.400
Right.

00:29:23.460 --> 00:29:24.200
I forgot about that.

00:29:24.200 --> 00:29:25.600
You have the reverse as well.

00:29:25.600 --> 00:29:29.900
You can say, I want to make sure in this situation, it never, ever calls this other function.

00:29:29.900 --> 00:29:30.500
Yeah.

00:29:30.500 --> 00:29:31.200
Right.

00:29:31.200 --> 00:29:31.640
Right.

00:29:31.640 --> 00:29:32.380
Yeah, that's true.

00:29:32.380 --> 00:29:34.140
That would be another good type of test.

00:29:34.140 --> 00:29:34.820
Okay.

00:29:34.820 --> 00:29:36.300
So, that's mocks.

00:29:36.300 --> 00:29:39.940
And then we have spies, which is next level stuff.

00:29:39.940 --> 00:29:40.140
Yeah.

00:29:40.140 --> 00:29:40.900
Yeah.

00:29:40.900 --> 00:29:42.560
I find them really hard to grasp.

00:29:42.560 --> 00:29:45.140
So, I haven't used spies yet myself.

00:29:45.140 --> 00:29:50.620
But from what I read, it's that spies are used to wrap real objects.

00:29:50.880 --> 00:29:54.860
And by default, they route all the method calls to the original object.

00:29:54.860 --> 00:30:01.120
So, they somewhat intercept and record all calls that are made to the real object.

00:30:01.120 --> 00:30:01.820
Yeah.

00:30:01.820 --> 00:30:02.280
Okay.

00:30:02.280 --> 00:30:09.900
So, this sounds like you might want to do those verification things that I was talking about, but not actually change the implementation.

00:30:09.900 --> 00:30:11.720
Just let it do what it's going to do.

00:30:11.720 --> 00:30:17.620
But you can kind of record that all the stuff was interacted with in certain ways or something like that.

00:30:17.620 --> 00:30:18.100
Yeah.

00:30:18.200 --> 00:30:27.860
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.

00:30:27.860 --> 00:30:29.360
That's what mocks are doing.

00:30:29.360 --> 00:30:29.860
Yeah.

00:30:29.860 --> 00:30:37.120
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.

00:30:37.120 --> 00:30:39.760
So, what are you going to return from them, right?

00:30:39.760 --> 00:30:46.820
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?

00:30:46.820 --> 00:30:54.060
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.

00:30:54.060 --> 00:30:55.340
Here's the answer.

00:30:55.340 --> 00:30:56.620
Here's the return value.

00:30:56.620 --> 00:30:59.940
Throw an exception if they try that or something along those lines.

00:31:00.340 --> 00:31:00.700
Exactly.

00:31:00.700 --> 00:31:01.400
Yeah.

00:31:01.400 --> 00:31:07.400
That said, I think it's, you know, there's certain types of errors you want to test for that are really tricky, right?

00:31:07.400 --> 00:31:10.740
Like, I want to see a SQL operational error.

00:31:10.740 --> 00:31:15.700
Like, hmm, how am I going to make it do that without talking to the real database?

00:31:16.220 --> 00:31:21.780
Well, you could come up with a mock that just says, if they call connect, throw this exception right away, right?

00:31:21.780 --> 00:31:23.280
Like, that would be a good example, I guess.

00:31:23.280 --> 00:31:24.000
Definitely.

00:31:24.000 --> 00:31:24.560
Okay.

00:31:24.560 --> 00:31:30.700
So, we have this spectrum of mocks, the dummies, the spies, the fakes, and so on.

00:31:30.700 --> 00:31:31.980
When should we use them?

00:31:31.980 --> 00:31:33.880
So, you can use a mock.

00:31:33.880 --> 00:31:42.160
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.

00:31:42.320 --> 00:31:46.560
But, yeah, you would use mocking whenever you don't actually want to call an object.

00:31:46.560 --> 00:31:56.680
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,

00:31:56.680 --> 00:32:00.940
and you have a function remove, which deletes that file again.

00:32:00.940 --> 00:32:06.940
Then when you test those methods, you don't actually want to write the file to disk every time the test runs.

00:32:07.160 --> 00:32:11.040
And the same holds for functions that remove objects.

00:32:11.040 --> 00:32:21.280
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.

00:32:21.280 --> 00:32:21.940
Yeah.

00:32:21.940 --> 00:32:32.760
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?

00:32:32.760 --> 00:32:33.320
Yeah.

00:32:33.680 --> 00:32:33.900
Yeah.

00:32:33.900 --> 00:32:39.920
I guess the other one is, if you need to reach down inside the system and make it do something unexpected.

00:32:39.920 --> 00:32:47.320
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.

00:32:47.320 --> 00:32:52.500
But with a mock, you can just say, if they call this function, throw this exception, see how the system deals with it, right?

00:32:52.820 --> 00:32:54.520
Yeah, that's also a very good use case.

00:32:54.520 --> 00:32:58.260
Yeah, I think testing errors, a lot of people don't test for errors.

00:32:58.260 --> 00:33:01.860
I feel like they're like, okay, well, this is what it's supposed to do, so let's test that.

00:33:01.860 --> 00:33:05.340
And I think testing for the opposite is almost as important.

00:33:05.340 --> 00:33:06.380
Yeah, definitely.

00:33:06.380 --> 00:33:06.880
I agree.

00:33:06.880 --> 00:33:07.960
Yeah, yeah, yeah.

00:33:07.960 --> 00:33:08.580
Cool.

00:33:09.040 --> 00:33:16.960
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.

00:33:16.960 --> 00:33:20.840
Yeah, so there are three core functionalities in the unit test.mock library.

00:33:20.840 --> 00:33:25.600
One is the class mock, one is the class magic mock, and then there is the patch function.

00:33:26.600 --> 00:33:32.380
And those have different properties, but maybe we can just go through them one by one.

00:33:32.380 --> 00:33:34.100
I think that's the easiest.

00:33:34.100 --> 00:33:35.080
Yeah, yeah.

00:33:35.080 --> 00:33:38.840
Well, if you think, okay, I'm going to mock something, you probably would start with the mock class, right?

00:33:38.840 --> 00:33:40.160
That's where you think you would start.

00:33:40.160 --> 00:33:41.900
Yeah, I think that's the best start.

00:33:41.900 --> 00:33:51.440
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.

00:33:52.040 --> 00:34:01.260
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.

00:34:01.260 --> 00:34:11.280
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.

00:34:11.280 --> 00:34:12.700
Let's call it fancy attribute.

00:34:12.700 --> 00:34:17.000
And it was just create a child mock and return it to you.

00:34:17.000 --> 00:34:20.100
So it would create this fancy attribute on the fly.

00:34:20.100 --> 00:34:29.200
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.

00:34:29.200 --> 00:34:30.840
And I really like that.

00:34:30.840 --> 00:34:32.160
I find that really fascinating.

00:34:32.160 --> 00:34:33.280
Yeah, it's quite interesting.

00:34:33.280 --> 00:34:35.980
And you don't have to do too much to set it up.

00:34:35.980 --> 00:34:38.980
You don't have to anticipate everything that's going to happen to it.

00:34:38.980 --> 00:34:43.200
You just create one, and if people think there's a function there, hey, guess what?

00:34:43.200 --> 00:34:44.880
All of a sudden, there's a function there.

00:34:45.120 --> 00:34:53.840
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.

00:34:53.840 --> 00:34:54.140
Yeah.

00:34:54.140 --> 00:34:54.620
Yeah.

00:34:54.940 --> 00:35:04.000
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.

00:35:04.500 --> 00:35:10.100
And yeah, there's also some problems with it, but I guess we can talk about that separately.

00:35:10.100 --> 00:35:11.020
Yeah, absolutely.

00:35:11.020 --> 00:35:19.260
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.

00:35:19.260 --> 00:35:22.940
It would be easy to create a mock and say, here's the mock database.

00:35:22.940 --> 00:35:24.080
You call stuff on it.

00:35:24.120 --> 00:35:26.400
It's just going to kind of go along with that.

00:35:26.400 --> 00:35:29.980
The challenge is, how do you provide that through, right?

00:35:29.980 --> 00:35:36.960
You know, I was talking about that crazy system that everything is passing every dependency everywhere abstractly, right?

00:35:36.960 --> 00:35:42.680
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.

00:35:42.680 --> 00:35:43.120
Yeah.

00:35:43.120 --> 00:35:46.640
And you have to configure it exactly like you want it to behave.

00:35:46.640 --> 00:35:47.220
Right.

00:35:47.220 --> 00:35:47.880
Right.

00:35:47.880 --> 00:35:51.320
If they call this with these parameters, return this value, right?

00:35:51.640 --> 00:35:55.660
Yeah, since that's also something I stumbled across in the beginning.

00:35:55.660 --> 00:35:59.560
So let's say you create a mock object that mocks the JSON library.

00:35:59.560 --> 00:36:04.100
So you would just have JSON equals mock, where mock is the class.

00:36:04.100 --> 00:36:10.640
And then you could just call JSON.dumps and give it any kind of argument you want to.

00:36:10.640 --> 00:36:14.380
But it's not the actual JSON.dumps method.

00:36:14.380 --> 00:36:16.760
So it has nothing to do with that implementation.

00:36:16.760 --> 00:36:21.520
And you could just give it any kind of input variables.

00:36:22.200 --> 00:36:24.760
And that's a bit confusing, I think, at the beginning.

00:36:24.760 --> 00:36:29.460
You have to understand that when you create a mock object and you haven't configured it yet,

00:36:29.460 --> 00:36:34.280
it has nothing to do with original function or class you're replacing.

00:36:34.280 --> 00:36:35.500
That's right.

00:36:35.500 --> 00:36:38.100
And the dumps, that one's fine, right?

00:36:38.100 --> 00:36:38.820
There's no problem.

00:36:38.820 --> 00:36:41.320
You usually don't care in a test what happens.

00:36:41.320 --> 00:36:46.940
But the reverse, the load, when it loads something, you've got to get something back to work with afterwards, right?

00:36:47.300 --> 00:36:47.700
Exactly.

00:36:47.700 --> 00:36:48.660
Yeah, that's tricky.

00:36:48.660 --> 00:36:52.680
The other thing, though, that you can do with these mocks is you can set a side effect.

00:36:52.680 --> 00:36:53.360
Yes.

00:36:53.360 --> 00:36:54.720
Which I think is actually cool.

00:36:54.720 --> 00:36:56.840
Yeah, you can set all kinds of things.

00:36:56.840 --> 00:36:58.560
So you can set a return value.

00:36:58.560 --> 00:36:59.880
We talked about that earlier.

00:36:59.880 --> 00:37:01.860
But also the exceptions.

00:37:01.860 --> 00:37:10.940
So when you, for example, want that a certain exception is thrown when you call the mock object, then you can just set a side effect.

00:37:10.940 --> 00:37:12.660
That's a property of the mock class.

00:37:12.660 --> 00:37:16.300
And then you can set it to any kind of exception you want.

00:37:16.660 --> 00:37:18.400
Yeah, that's a really good way to test.

00:37:18.400 --> 00:37:22.020
If this error happens at this function call, what are we going to do?

00:37:22.020 --> 00:37:22.760
Yeah, it's great.

00:37:22.760 --> 00:37:25.360
So we've got, that's the standard mock.

00:37:25.360 --> 00:37:34.800
And when you call one of these functions, like you said, let's say JSON load us, it'll give you back something, probably, which is another mock.

00:37:34.960 --> 00:37:38.340
But if you print it out, it'll just say that it's a mock of that.

00:37:38.340 --> 00:37:41.280
And it has, you know, just be kind of useless, right?

00:37:41.280 --> 00:37:41.920
Yeah.

00:37:41.920 --> 00:37:45.140
So the next level up would be to bring in some magic.

00:37:45.140 --> 00:37:45.740
Yeah.

00:37:45.740 --> 00:37:52.460
So there is the second class called magic mock, which is actually subclass of the mock class.

00:37:52.460 --> 00:37:57.140
But it contains all the magic methods pre-created and ready to use.

00:37:57.140 --> 00:38:03.960
So, for example, if you want to compute the length of an object, then the magic mock could be very useful.

00:38:03.960 --> 00:38:08.200
Since the dunder len, how do you call that in English?

00:38:08.200 --> 00:38:09.920
Dunder len, I guess?

00:38:09.920 --> 00:38:10.520
Len?

00:38:10.520 --> 00:38:10.980
Yeah.

00:38:10.980 --> 00:38:12.300
Let's call it dunder len.

00:38:12.300 --> 00:38:16.120
It's already pre-implemented and ready to use.

00:38:16.120 --> 00:38:16.640
Yeah.

00:38:16.640 --> 00:38:17.560
Yeah, exactly.

00:38:17.560 --> 00:38:24.020
So all the so-called magic methods, dunder stir, dunder len, dunder repper, all those things are there, right?

00:38:24.020 --> 00:38:24.680
Yes.

00:38:24.680 --> 00:38:29.960
And usually I use the mock class if I don't need magic methods.

00:38:29.960 --> 00:38:31.740
And otherwise I use the magic mock.

00:38:32.160 --> 00:38:37.980
But when you look, for example, a step further and you look at the patch method, that actually returns a magic mock.

00:38:38.120 --> 00:38:44.880
So you're also fine using the magic mock, but it's then sometimes implementing things that you actually don't need.

00:38:44.880 --> 00:38:45.720
Right, right.

00:38:45.720 --> 00:38:47.100
Maybe that makes it a little bit slower.

00:38:47.100 --> 00:38:47.580
I don't know.

00:38:47.580 --> 00:38:48.700
I haven't tried, but possibly.

00:38:48.700 --> 00:38:50.080
Yeah, that might be the case.

00:38:50.080 --> 00:38:51.680
I also haven't tried it yet.

00:38:52.640 --> 00:38:53.140
All right.

00:38:53.140 --> 00:38:59.140
So the one that I end up using directly most often, it's got to be the patch.

00:38:59.140 --> 00:39:01.200
Unit test.mock.patch, right?

00:39:01.200 --> 00:39:06.320
This one is the, I'm not going to pass a bunch of things around, but just reach down inside this thing.

00:39:06.320 --> 00:39:09.700
I know it's going to try to call this function or create one of these things.

00:39:09.700 --> 00:39:12.860
Just make that at whatever level it's going to be down there.

00:39:12.860 --> 00:39:13.700
Just make that work.

00:39:13.700 --> 00:39:16.940
You know, make that go away or make it return this value instead and so on.

00:39:17.240 --> 00:39:23.980
Yeah, I also mostly use the patch method and I like it because you can be very specific about what you want to actually patch.

00:39:23.980 --> 00:39:32.460
So it's very easy to see from the patch statement where you're going in the code to change its behavior.

00:39:32.460 --> 00:39:40.960
And I think I like this being most precise or as precise as possible with the mocking or the patching.

00:39:40.960 --> 00:39:45.920
Yeah, and I feel like it doesn't force you into these design patterns like I described.

00:39:46.200 --> 00:39:54.920
Like just explode in complexity and say, well, if you're going to have a dependency that you want to replace, you have to pass the dependencies around so you can pass the mock versions of them.

00:39:54.920 --> 00:39:59.900
And that's fine when there's one, but then one thing requires two more, which requires four.

00:39:59.900 --> 00:40:02.400
And it just explodes into like all this stuff, right?

00:40:02.400 --> 00:40:09.820
And so with patch, you don't have to have the structure of every single possible dependencies passed everywhere it goes.

00:40:09.820 --> 00:40:15.700
You can just say, if you see this function called or this object created deep down inside, do this instead.

00:40:16.020 --> 00:40:16.160
Yeah.

00:40:16.160 --> 00:40:19.300
So that's also actually what the patch function is doing.

00:40:19.300 --> 00:40:26.520
So it looks up, you give it a path and it looks up the object in this given module and replaces that object with a magic mock.

00:40:27.040 --> 00:40:42.380
So it's by default a new magic mock, but you can also configure this so you can create some class or then configure the patch statement such that it returns not a magic mock, but an instance of the class that you hand it.

00:40:42.380 --> 00:40:43.420
Oh, interesting.

00:40:43.580 --> 00:40:48.920
So you can say, I'm going to get like a little test double like sort of thing that I'm going to create.

00:40:48.920 --> 00:40:53.820
And if I call this function, it has this little fake implementation or something and just say use that?

00:40:53.820 --> 00:40:54.460
Yes.

00:40:54.460 --> 00:40:56.320
So you don't have to use the magic mock.

00:40:56.320 --> 00:40:56.920
Okay.

00:40:57.300 --> 00:40:58.140
Yeah, that's pretty cool.

00:40:58.140 --> 00:40:59.400
Actually, I didn't realize I could do that.

00:40:59.400 --> 00:41:01.060
There's different ways you can use it.

00:41:01.060 --> 00:41:04.260
It could be a decorator, context manager, other stuff, right?

00:41:04.260 --> 00:41:04.660
Yeah.

00:41:04.660 --> 00:41:13.100
So the syntax in general is that you have patch and then in brackets and as a string, you have package.module.target.

00:41:13.100 --> 00:41:19.520
And there's a really nice example from one of the PyCon talks from Lisa Roach, I think.

00:41:19.520 --> 00:41:21.940
It's called demystifying the patch function.

00:41:21.940 --> 00:41:22.980
I really like that talk.

00:41:22.980 --> 00:41:24.440
We can also link it in the show notes.

00:41:24.440 --> 00:41:24.880
Yeah.

00:41:24.880 --> 00:41:30.000
And yeah, so let's say you have an example file, which is called just example.py.

00:41:30.000 --> 00:41:34.560
And you have one import statement from db, import dbwrite.

00:41:34.560 --> 00:41:36.800
So you want to write to some database.

00:41:36.800 --> 00:41:41.300
And then you have a single function, which is called foo or whatever you want to call it.

00:41:41.300 --> 00:41:47.760
And it just calls dbwrite and returns the return value that you get from dbwrite.

00:41:47.760 --> 00:41:52.140
I like this example because it's so simple, but it actually uncovers some tricky bits.

00:41:52.140 --> 00:41:55.100
Yeah, it brings the point across very well.

00:41:55.100 --> 00:42:00.380
And it's so easy to understand since you don't actually have to care about how dbwrite is implemented,

00:42:00.380 --> 00:42:04.980
but you know it writes to database and that's something that you don't want to do in the test.

00:42:04.980 --> 00:42:05.800
Yeah, exactly.

00:42:05.800 --> 00:42:06.440
Yeah.

00:42:06.440 --> 00:42:12.360
So we, in this case, we would want to patch or mock the dbwrite call.

00:42:12.360 --> 00:42:14.780
And you can do that with a decorator.

00:42:14.780 --> 00:42:18.720
You can do that with context manager or with manual starting and stopping.

00:42:18.720 --> 00:42:22.600
And which one you use would depend on the scope.

00:42:22.600 --> 00:42:27.760
So how the scope looks like that you want the object to be patched in.

00:42:27.760 --> 00:42:28.200
Yeah.

00:42:28.200 --> 00:42:32.460
So it seems like there's a couple of ways that are pretty straightforward, kind of comparable.

00:42:32.460 --> 00:42:37.080
You could do a decorator and say on your test function, put the decorator, say patch this,

00:42:37.080 --> 00:42:39.020
this object or this function call.

00:42:39.100 --> 00:42:41.900
Or you could do a context manager inside your test function.

00:42:41.900 --> 00:42:49.580
And I guess it really depends on how many things are you patching, how complicated is it to set up some of the stuff and so on.

00:42:49.580 --> 00:42:51.280
But they seem pretty comparable, those two.

00:42:51.280 --> 00:42:53.820
And the other is I could turn it on and turn it off.

00:42:54.140 --> 00:42:58.360
But this is a system-wide change of what that function means.

00:42:58.360 --> 00:43:09.920
And so if for some reason the test fails and you don't have a try finally to turn it off or something like that, it's going to be bad because it'll permanently change what that function means, which maybe you only wanted it for a few.

00:43:09.920 --> 00:43:10.280
Yeah.

00:43:10.420 --> 00:43:14.560
But I guess the scenario I see that you might want to do it is like test set up and test tear down.

00:43:14.560 --> 00:43:18.380
Like for this whole class, we're going to just set it up and no one has to worry about it.

00:43:18.380 --> 00:43:19.880
You just write all the tests.

00:43:19.880 --> 00:43:22.660
So maybe that's the turn it on, turn it off scenario.

00:43:22.660 --> 00:43:26.480
Yeah, I think that was also the scenario where I've seen it.

00:43:26.480 --> 00:43:28.300
Since then it can be useful.

00:43:28.300 --> 00:43:34.120
Otherwise, you would always have to apply the patch decorator again or use it to context manager in each test.

00:43:34.120 --> 00:43:35.360
And that looks very messy.

00:43:35.540 --> 00:43:41.560
And if you can just do it centrally in a single place, that's, I think, the nicest solution.

00:43:41.560 --> 00:43:47.560
Yeah, and it can get super complicated about setting these things up because first you're going to call this and it needs to return that value.

00:43:47.560 --> 00:43:52.240
But if it gets called with other value, then return the, like there's a lot of stuff that can get done on these.

00:43:52.240 --> 00:43:54.480
And it's, you know, maybe simple for one.

00:43:54.480 --> 00:43:59.280
But if you have three or four of them, all of a sudden, like there's a lot of setup to do a little test.

00:43:59.280 --> 00:43:59.680
Yeah.

00:43:59.680 --> 00:44:05.520
And it can also become messy to have all these patch statements stacked on top of each other.

00:44:05.520 --> 00:44:10.620
I think two or three are maybe fine, but then it becomes really messy.

00:44:10.620 --> 00:44:11.180
Yeah.

00:44:11.180 --> 00:44:12.200
Yeah, absolutely.

00:44:12.200 --> 00:44:21.120
So I guess I'm starting to come around to the idea of having it just set up in the test setup or maybe a test fixture in pytest or something like that.

00:44:21.120 --> 00:44:22.580
Yeah, that's also a nice way.

00:44:22.580 --> 00:44:23.100
Yeah.

00:44:23.100 --> 00:44:33.040
Another thing that I think is interesting about this example is it seems so simple, but you have to be a little bit aware of how those functions are being used internally.

00:44:33.300 --> 00:44:33.780
Right.

00:44:33.780 --> 00:44:39.240
So the import statement in the example that you talked about says from DB import DB write.

00:44:39.240 --> 00:44:46.960
And you have to explicitly say in a string the full like namespace style name of the thing that it's going to patch.

00:44:46.960 --> 00:44:50.960
So in this example, you would say example dot DB write.

00:44:50.960 --> 00:44:52.540
And if you get it wrong, it crashes.

00:44:52.540 --> 00:44:52.880
Right.

00:44:52.880 --> 00:44:57.100
Yeah, I think that's what most people find confusing in the beginning.

00:44:57.100 --> 00:45:05.880
But I think it's great because you start to understand what it means if you import something and what is happening in the program.

00:45:06.080 --> 00:45:15.360
And I found it very helpful to just inspect then the module and what kind of attributes it has.

00:45:15.360 --> 00:45:20.240
So it is important to know that you have to patch where the object is looked up.

00:45:20.460 --> 00:45:22.980
And this might not be the place where it is defined.

00:45:22.980 --> 00:45:37.220
So if we have this DB write example where you have the from DB import DB write statement in the file example dot pi, then you are importing the DB write function from the DB module.

00:45:37.980 --> 00:45:45.980
So the consequence is that the example module now knows about the DB write method, but it does not know about DB.

00:45:45.980 --> 00:45:51.060
So if you patch it, but I think it's nice that you can see that actually.

00:45:51.060 --> 00:45:58.520
So if you open an IPython shell and you import this example module, then you can call directory.

00:45:58.520 --> 00:45:59.940
So dear, dir.

00:45:59.940 --> 00:46:00.600
Yeah.

00:46:00.600 --> 00:46:01.580
How do you pronounce that?

00:46:01.580 --> 00:46:04.040
I would say dir, but I could be wrong.

00:46:04.040 --> 00:46:04.200
Yeah.

00:46:04.200 --> 00:46:04.380
Dir.

00:46:04.380 --> 00:46:05.120
Okay.

00:46:05.120 --> 00:46:06.600
I will trust you on that.

00:46:07.020 --> 00:46:13.360
So you would call dir example, and then you would see a list of the attributes for this example module.

00:46:13.360 --> 00:46:17.960
And there you will see DB write and foo, but you won't see DB.

00:46:17.960 --> 00:46:26.740
So therefore, to mock the call to the DB write function in the test, you would have to patch example dot DB write.

00:46:26.740 --> 00:46:27.420
Right.

00:46:27.420 --> 00:46:35.900
And it's tricky because conceptually, what you think you're patching is the DB write thing out of the DB module.

00:46:36.060 --> 00:46:42.220
So my first thought was, well, that should probably be just DB dot write, but that doesn't work in this case.

00:46:42.220 --> 00:46:42.720
Yeah.

00:46:42.720 --> 00:46:51.540
But what's interesting is if they had said import DB, and then in the implementation of foo, they said DB dot DB write, then it would work.

00:46:51.540 --> 00:46:59.040
And actually, this example where you say example dot DB write, patch that, it would crash and say, well, that thing doesn't have this function, so we can't patch it.

00:46:59.360 --> 00:47:03.120
And so you have to be a little bit aware of how these are written.

00:47:03.120 --> 00:47:06.560
And like you said, where they're defined, it does take a little bit of awareness.

00:47:06.560 --> 00:47:09.680
So I think you can look with dir, which is great.

00:47:09.680 --> 00:47:12.640
You just also have to just be a little bit aware of what's going on there.

00:47:12.640 --> 00:47:16.320
Yeah, I think once you wrap your head around it, then it's easy.

00:47:16.320 --> 00:47:27.240
Once you understand the basic idea and you have used it a few times, then it would become natural or much easier to understand which patch statement you have to use.

00:47:27.240 --> 00:47:36.580
Yeah, I think we can look at another example where you would not import from DB import DB write, but you would just import the DB module.

00:47:36.580 --> 00:47:42.760
And then the foo function would call DB dot DB write instead of just DB write.

00:47:42.760 --> 00:47:48.180
And now the example module knows about DB, but not DB write.

00:47:48.180 --> 00:47:56.780
So again, if you would call dir on example, you would get DB and foo in the namespace, but you would not have DB write.

00:47:57.160 --> 00:48:05.640
So now when you patch it, you would either have to use example dot DB dot DB write or just DB dot DB write.

00:48:05.640 --> 00:48:13.060
And yeah, it can be a bit confusing, but I think that's also the hardest thing to understand.

00:48:13.060 --> 00:48:17.540
And once you get that, then you have the most important idea.

00:48:17.540 --> 00:48:17.980
Right.

00:48:17.980 --> 00:48:20.000
Once you understand it, it's not too bad, I think.

00:48:20.000 --> 00:48:20.820
But it does.

00:48:20.820 --> 00:48:24.780
You do have to put some ideas together to figure out what to put there.

00:48:24.780 --> 00:48:25.280
Yeah.

00:48:25.460 --> 00:48:36.020
One of the challenges, I think, of the more that you kind of reach inside of things and you make these changes, like we're saying here, your testing can become a little bit harder to maintain.

00:48:36.020 --> 00:48:40.580
So, for example, suppose we have the first scenario where they had the from DB import DB write.

00:48:40.580 --> 00:48:41.820
Everything was fine.

00:48:41.820 --> 00:48:47.840
And then somebody decides we're going to refactor the code to be more explicit and use the namespaces.

00:48:47.840 --> 00:48:55.880
And then they go change the example pi to use the different types of imports and rewrite the functions to say DB dot DB write versus just the function call.

00:48:55.880 --> 00:48:57.800
All of a sudden, your test doesn't work anymore.

00:48:57.800 --> 00:48:59.240
You're like, what is going on here?

00:48:59.240 --> 00:49:01.500
And that's just the nature of this mocking stuff.

00:49:01.620 --> 00:49:08.020
Like, as you reach inside to make these changes, you're now somewhat dependent on the structure of the inside.

00:49:08.020 --> 00:49:08.540
Yeah.

00:49:08.540 --> 00:49:09.260
Yeah.

00:49:09.260 --> 00:49:11.700
You always have to keep that in mind when you adapt the code.

00:49:11.700 --> 00:49:12.140
Yeah.

00:49:12.240 --> 00:49:15.540
So, I guess maybe try to do as little as possible.

00:49:15.540 --> 00:49:21.040
I mean, sometimes you have to do it to not talk to Google Cloud or not to charge the credit card for real.

00:49:21.040 --> 00:49:25.340
But, you know, don't if you can avoid it, do so maybe.

00:49:25.340 --> 00:49:27.560
I don't know, because it's just one more dependency, right?

00:49:27.560 --> 00:49:28.180
Yes.

00:49:28.180 --> 00:49:31.700
Well, what about using mock versus patch?

00:49:31.700 --> 00:49:34.700
So, I don't think there are any clear rules.

00:49:34.700 --> 00:49:37.880
At least I have not come across any clear rules.

00:49:37.880 --> 00:49:43.080
I guess that's similar to the whole topic that it's somewhat controversial.

00:49:43.080 --> 00:49:47.420
But personally, I mostly use patch, just as you just said.

00:49:47.420 --> 00:49:51.300
I like it since it's so specific, and I rarely use mock.

00:49:51.300 --> 00:49:54.900
And I don't think I ever use magic mock specifically.

00:49:54.900 --> 00:50:00.980
So, I use mock if we have this dependency injection we talked about in the very beginning.

00:50:00.980 --> 00:50:07.780
For example, if you have a client, and I use clients to interact with Google Cloud,

00:50:07.780 --> 00:50:13.360
and then I can just, instead of passing in the client, I can just pass in a mock object.

00:50:13.360 --> 00:50:18.300
But in all the other cases, I use the patch function.

00:50:18.300 --> 00:50:21.460
Yeah, I would totally, 100% agree with that.

00:50:21.460 --> 00:50:27.080
And I think in Python, this place where you pass in all of your dependencies,

00:50:27.080 --> 00:50:29.480
it's less common than other languages.

00:50:29.480 --> 00:50:32.120
So, I think that naturally makes patch a little more common.

00:50:32.120 --> 00:50:34.140
Yeah, that might be the reason.

00:50:34.140 --> 00:50:36.480
Yeah, which is generally a good thing.

00:50:36.480 --> 00:50:41.160
Also, I think some other languages, it's very hard for them to do this idea of patching.

00:50:41.160 --> 00:50:43.580
So, they have to pass all their stuff around.

00:50:43.580 --> 00:50:48.600
So, we've talked a little bit about some of the challenges.

00:50:48.600 --> 00:50:53.840
And like, if the import statement's like this, you got to mirror that in the way that you write your patch statement.

00:50:53.840 --> 00:50:55.120
And if it changes, that changes.

00:50:55.120 --> 00:50:59.660
But there's also some other common problems and some things to keep in mind.

00:50:59.660 --> 00:51:00.940
You want to run us through those?

00:51:01.300 --> 00:51:01.760
Yeah, sure.

00:51:01.760 --> 00:51:04.700
So, we saw that we can configure mock objects.

00:51:04.700 --> 00:51:08.860
So, we can set the return value, side effects like exceptions and so on.

00:51:09.460 --> 00:51:16.560
And the fact that the mock objects create attributes and methods on the fly makes them very sensitive to mistakes.

00:51:16.560 --> 00:51:20.720
So, a typical example is that you misspell something.

00:51:20.720 --> 00:51:27.760
So, for example, you can call assert called once on a patch or mocked object.

00:51:28.560 --> 00:51:31.240
And you could just have a spelling mistake there.

00:51:31.240 --> 00:51:36.460
For example, you could have assert called once with a single S instead of assert called once.

00:51:36.460 --> 00:51:38.780
But the test will just pass.

00:51:38.780 --> 00:51:48.080
It won't raise an assertion error because you just created a new method on the mock object that is called assert called once instead of calling the actual function.

00:51:48.080 --> 00:51:55.180
Yeah, and this is really tricky because the successful behavior is exactly the same as just calling a function that doesn't exist.

00:51:55.180 --> 00:51:56.080
It's just do nothing.

00:51:56.080 --> 00:51:57.080
It's fine.

00:51:57.080 --> 00:52:00.500
But the verification won't happen, right?

00:52:00.500 --> 00:52:03.340
Because only the verification will happen if you actually call the right one.

00:52:03.340 --> 00:52:03.940
Yeah.

00:52:04.220 --> 00:52:10.260
I think also a typical problem is that a mock object does not know the interface of your class.

00:52:10.260 --> 00:52:19.700
That's also what I tried to explain earlier, that you have to understand that the mock object actually has nothing to do with the class that it replaces.

00:52:19.700 --> 00:52:23.840
But you have to configure it to behave like your class.

00:52:23.840 --> 00:52:33.340
So, let's say going back to the spell class, when we called dir on the mocked object, then you can see all the kinds of attributes.

00:52:34.060 --> 00:52:43.000
So, maybe like if you have IPython open again and you would import the spell class, you would import the patch function from unit test.mock.

00:52:43.000 --> 00:52:52.780
And then you can just look at the attributes of a mocked spell instance by calling with patch and then spell class.spell as mocked spell.

00:52:52.780 --> 00:52:55.180
That would just be the name of this mocked object.

00:52:55.180 --> 00:52:59.900
And then you could print the call of dir on the mocked spell object.

00:53:00.120 --> 00:53:03.360
And then you would see all these different things that you can use.

00:53:03.360 --> 00:53:08.160
Assert any call, assert call once, assert call once with, and so on.

00:53:08.160 --> 00:53:09.140
But you would actually...

00:53:09.140 --> 00:53:11.900
Yeah, but none of them have anything to do with spell.

00:53:11.900 --> 00:53:13.620
Yes.

00:53:14.060 --> 00:53:21.560
So, you wouldn't see all the methods that are included in the spell class, like save, remove, or cast.

00:53:21.560 --> 00:53:23.100
Of course, you have to cast a spell.

00:53:23.100 --> 00:53:24.500
Be able to cast a spell.

00:53:24.500 --> 00:53:31.480
And that can be quite tricky, since it can lead to behavior that you don't want.

00:53:31.840 --> 00:53:38.700
So, the magic mocked object that's returned by the patch call, which is completely unrelated to the spell class.

00:53:38.700 --> 00:53:39.180
Yeah.

00:53:39.180 --> 00:53:40.580
And that's really tricky.

00:53:40.580 --> 00:53:44.980
So, I've seen spec equals true in various testing things.

00:53:44.980 --> 00:53:48.880
And I didn't, until just now, really put together what that actually did.

00:53:48.880 --> 00:53:51.380
So, you can sort of fix that sometimes.

00:53:51.380 --> 00:53:52.040
Yes.

00:53:52.040 --> 00:53:56.720
So, some of the problems can be solved, at least those with the spelling mistakes,

00:53:56.720 --> 00:54:00.800
and also that you want your class to somewhat look like the...

00:54:00.800 --> 00:54:05.980
Or you want your mock to look somewhat like the class that it's replacing.

00:54:05.980 --> 00:54:09.860
You can use the spec equals true attribute in the patch call.

00:54:09.860 --> 00:54:14.800
And this will cause the magic mock to look like the object that is being patched.

00:54:14.800 --> 00:54:19.380
So, it would cause this misspelled assert call once to raise an exception.

00:54:19.780 --> 00:54:24.740
And also, you can only call methods with the correct arguments.

00:54:24.740 --> 00:54:28.600
And you can only call methods that actually exist in the class.

00:54:28.600 --> 00:54:29.580
Yeah, exactly.

00:54:29.580 --> 00:54:33.700
So, one of the problems with these mocks could be, inside a function,

00:54:33.700 --> 00:54:40.060
you're calling something on what you think is the real spell or the data access layer or whatever.

00:54:40.060 --> 00:54:43.940
And you're calling a function that doesn't exist or you misspelled it.

00:54:43.940 --> 00:54:48.660
And all of your tests pass because the mock is like, fine.

00:54:48.660 --> 00:54:50.160
We'll just...

00:54:50.160 --> 00:54:52.760
You called a function that didn't exist, just like all the others.

00:54:52.760 --> 00:54:55.600
So, we're just going to return a mock object there.

00:54:55.600 --> 00:55:00.600
But in production, when it really goes to run and it gets a real thing that has no method there,

00:55:00.600 --> 00:55:01.400
it's going to crash.

00:55:01.580 --> 00:55:07.500
So, with the spec equals true, you can be a little more restrictive and catch some of those errors as well, maybe.

00:55:07.500 --> 00:55:08.100
Yeah.

00:55:08.100 --> 00:55:12.560
What I find in the beginning when I saw spec equals true, I thought, oh, this is great.

00:55:12.560 --> 00:55:15.640
Then I just have exactly the thing I'm patching.

00:55:16.280 --> 00:55:22.200
But it turns out, yeah, almost, that all the attributes you create in the constructor,

00:55:22.200 --> 00:55:27.620
so in the __init__() call, are not contained in the mocked class in the end.

00:55:27.620 --> 00:55:31.720
So, that's due to the internal workings of spec and auto spec.

00:55:31.720 --> 00:55:34.400
And I think there's also spec set.

00:55:34.400 --> 00:55:35.740
I'm not sure how it works.

00:55:35.740 --> 00:55:43.780
But when you use that in the end, your mock object does not know about any of this dynamically created attributes.

00:55:44.180 --> 00:55:49.540
Yeah, really, the only way it would know is either if it disassembled the constructor,

00:55:49.540 --> 00:55:53.340
which would be kind of weird, or if it actually called the constructor.

00:55:53.340 --> 00:55:58.700
And those constructors could have side effects like creating files or trying to open a database or whatever, right?

00:55:58.700 --> 00:56:00.900
So, it can't really do those.

00:56:00.900 --> 00:56:02.060
So, it can't see them.

00:56:02.060 --> 00:56:05.980
I guess if you really wanted it to work exactly in that way,

00:56:05.980 --> 00:56:11.780
you could put all the field definitions as type level, as class level stuff,

00:56:11.780 --> 00:56:12.960
and then just set them, right?

00:56:13.280 --> 00:56:14.820
That's not as common in Python.

00:56:14.820 --> 00:56:16.660
Sometimes it is, sometimes it isn't.

00:56:16.660 --> 00:56:18.680
But that would be the way to fix it, I guess.

00:56:18.680 --> 00:56:19.220
Yeah.

00:56:19.220 --> 00:56:23.820
So, yeah, spec and spec set, like auto spec, spec set, spec,

00:56:23.820 --> 00:56:26.060
they can be used to solve some of these problems.

00:56:26.060 --> 00:56:29.780
But you should be aware that they also create problems

00:56:29.780 --> 00:56:32.800
that you might not be aware of in the beginning.

00:56:32.800 --> 00:56:36.040
And also, I think it will slow down testing.

00:56:36.180 --> 00:56:40.480
I have not noticed that really, that it slows them down a lot.

00:56:40.480 --> 00:56:43.740
But I guess it depends on how much you actually use this functionality.

00:56:43.740 --> 00:56:44.980
Yeah, yeah, for sure.

00:56:44.980 --> 00:56:51.560
How much are you doing computationally in your test versus just a whole bunch of creation of mocks to just call one little function?

00:56:51.560 --> 00:56:51.820
Yeah.

00:56:51.820 --> 00:56:55.760
I also like besides spec and auto spec and all these other things,

00:56:55.760 --> 00:57:00.160
there is so much more that you can do with patching and mocking.

00:57:00.160 --> 00:57:02.560
And it's a huge topic.

00:57:02.560 --> 00:57:10.160
I guess you can have a whole another podcast about how to prevent mocking or how not to get into mock hell.

00:57:10.160 --> 00:57:11.860
There's also PyCon talk on this.

00:57:11.860 --> 00:57:14.040
It's just, yeah, it's a huge topic.

00:57:14.040 --> 00:57:17.300
Yeah, I can definitely see being a mock hell.

00:57:17.300 --> 00:57:18.580
I've been on both sides of it.

00:57:18.580 --> 00:57:25.300
And I think Python has a pretty good middle ground with the ability to patch stuff and not completely rewrite your code to deal with it.

00:57:25.300 --> 00:57:27.080
Yeah, it's pretty nice.

00:57:27.080 --> 00:57:28.660
Yeah, I also like using it.

00:57:28.660 --> 00:57:29.500
Yeah, cool.

00:57:29.500 --> 00:57:30.500
All right.

00:57:30.500 --> 00:57:35.080
Well, maybe you want to do a quick wrap up, just summarize all that before we wrap things up?

00:57:35.080 --> 00:57:35.960
Yes, sure.

00:57:35.960 --> 00:57:39.700
So I guess we learned that mocking is controversial.

00:57:39.700 --> 00:57:44.880
And that it should be used with care, not to just fix your badly written code.

00:57:44.880 --> 00:57:51.580
There are a few ways in which you can design your code such that you don't need patching all the time,

00:57:51.580 --> 00:57:58.640
like the dependency injection we talked about, where you pass in a mock to client, as an example.

00:57:58.640 --> 00:57:59.120
Yeah.

00:57:59.120 --> 00:57:59.640
Oh, yeah.

00:57:59.640 --> 00:58:03.740
And we talked about these different naming conventions that you should not get confused by them.

00:58:03.740 --> 00:58:09.440
And maybe if you think it's unnecessarily complicated, then just don't use them.

00:58:09.440 --> 00:58:10.220
That's also fine.

00:58:10.220 --> 00:58:12.700
There are people on both sides of the spectrum.

00:58:12.700 --> 00:58:20.400
Yeah, I've always found that the distinction, trying to be very precise about, oh, no, this is a mock and this is a fake and this is a stub.

00:58:20.400 --> 00:58:24.800
It doesn't necessarily help you, but it just makes things a little bit messy.

00:58:24.800 --> 00:58:26.340
Like, you know what you're trying to do?

00:58:26.440 --> 00:58:38.240
To me, the big distinction is, are you just trying to stop something from being called and maybe just return a value or create a side effect versus are you trying to understand what functions have been called?

00:58:38.240 --> 00:58:43.280
Like, I want to make sure they always, always call, you know, check for admin or something like that.

00:58:43.280 --> 00:58:43.420
Right.

00:58:43.500 --> 00:58:44.980
Like, that to me is a big distinction.

00:58:44.980 --> 00:58:47.820
Are you trying to observe the behavior or just the outcome?

00:58:47.820 --> 00:58:48.780
Yeah, I agree.

00:58:48.780 --> 00:58:51.280
It's also because there are no clear cut definitions.

00:58:51.280 --> 00:58:52.820
It's all a bit blurry.

00:58:53.280 --> 00:58:56.980
And the definitions are, in some cases, similar.

00:58:56.980 --> 00:59:02.340
So, it can be really hard to tear them apart and understand what each one is about.

00:59:02.340 --> 00:59:02.940
Yeah.

00:59:03.280 --> 00:59:10.780
So, we also talked about the library, the mocking library, unit test.mock, and the three core functionalities, mock, magic, mock, and patch.

00:59:10.780 --> 00:59:14.740
And mocking can be or seem confusing in the beginning.

00:59:14.740 --> 00:59:26.180
But once you understand the basics, for example, that you have to patch where something is used, which might not be where it's defined, then it can be really helpful, especially with production code.

00:59:26.180 --> 00:59:27.320
And I see that every day.

00:59:27.320 --> 00:59:27.800
Yeah.

00:59:27.800 --> 00:59:28.240
Awesome.

00:59:28.240 --> 00:59:33.260
Well, this is definitely a very powerful tool in the testing tool set.

00:59:33.260 --> 00:59:39.560
And it can make testing possible where it was impossible or much easier where it was previously really, really hard.

00:59:39.560 --> 00:59:44.280
So, hopefully, this helps people write more testable code and test more of their code.

00:59:44.280 --> 00:59:44.720
Yeah.

00:59:44.720 --> 00:59:52.420
And maybe at least motivate them to look into what mocking is and maybe see that they can use it as well.

00:59:52.420 --> 00:59:53.060
Absolutely.

00:59:53.060 --> 00:59:53.960
All right.

00:59:53.960 --> 00:59:57.560
Before we call the show, you're going to write some Python code, mock out some libraries,

00:59:57.560 --> 00:59:58.820
what editor do you use?

00:59:58.820 --> 01:00:00.120
I still use Vim.

01:00:00.120 --> 01:00:03.420
Like, I think I will use it the rest of my life.

01:00:03.420 --> 01:00:05.120
It's hard to get away from it.

01:00:05.120 --> 01:00:08.200
All of my colleagues use PyCharm now, or most of them.

01:00:08.200 --> 01:00:11.580
But yeah, I will still continue using Vim.

01:00:11.580 --> 01:00:12.060
Awesome.

01:00:12.060 --> 01:00:14.720
And the notable PyPI package or library?

01:00:14.720 --> 01:00:16.920
Yeah, I guess I have to say unit test.mock.

01:00:17.400 --> 01:00:24.100
But one thing I really like is that I was always using the IPython debugger for debugging.

01:00:24.100 --> 01:00:29.460
But a few, like a month back, I switched to PDB++.

01:00:29.460 --> 01:00:30.060
Yeah.

01:00:30.060 --> 01:00:33.120
We can also link that in the show notes if people don't know it yet.

01:00:33.120 --> 01:00:34.920
And what I really like it.

01:00:34.920 --> 01:00:36.780
So, it's very easy to install.

01:00:36.780 --> 01:00:39.860
It just wraps around the standard PDB debugger.

01:00:40.240 --> 01:00:42.300
And it has a few nice features.

01:00:42.300 --> 01:00:44.880
I mostly love the sticky command.

01:00:44.880 --> 01:00:46.440
And when you...

01:00:46.440 --> 01:00:48.740
So, you enter the debugger and you type sticky.

01:00:48.740 --> 01:00:50.100
And then you will...

01:00:50.100 --> 01:00:56.180
While you're debugging, you will see the code command stick to the top of the screen.

01:00:56.180 --> 01:01:00.900
And you can really see where you are in your code, stepping through the lines one by one.

01:01:00.900 --> 01:01:03.640
And I find that very helpful when debugging.

01:01:03.640 --> 01:01:04.640
Yeah, that's cool.

01:01:04.640 --> 01:01:10.660
It's like a little bit of a blend between a GUI debugger and a command line style debugger.

01:01:10.660 --> 01:01:11.180
Yeah.

01:01:11.180 --> 01:01:11.820
Yeah, yeah.

01:01:11.820 --> 01:01:12.160
Very good.

01:01:12.160 --> 01:01:13.180
I don't think I've heard of that one.

01:01:13.180 --> 01:01:13.940
That's excellent.

01:01:13.940 --> 01:01:14.280
Thanks.

01:01:14.280 --> 01:01:14.840
All right.

01:01:14.840 --> 01:01:15.580
Final call to action.

01:01:15.580 --> 01:01:17.160
People trying to write some tests.

01:01:17.160 --> 01:01:17.800
They want to get out there.

01:01:17.800 --> 01:01:18.560
They want to use mocking.

01:01:18.560 --> 01:01:19.160
What do they do?

01:01:19.160 --> 01:01:21.520
I think a good start is the documentation.

01:01:21.520 --> 01:01:24.880
I think it's a very comprehensive one.

01:01:25.180 --> 01:01:28.000
There's also a real Python...

01:01:28.000 --> 01:01:28.680
How do you call it?

01:01:28.680 --> 01:01:30.220
Blog post on the topic.

01:01:30.220 --> 01:01:30.680
Yeah.

01:01:30.680 --> 01:01:34.180
I think those two places are good to start.

01:01:34.180 --> 01:01:35.020
I just...

01:01:35.020 --> 01:01:36.740
In general, I like the Python documentation.

01:01:36.740 --> 01:01:37.940
I always...

01:01:37.940 --> 01:01:40.340
In most cases, it's just the best source.

01:01:40.340 --> 01:01:40.900
Yeah.

01:01:40.900 --> 01:01:41.320
Awesome.

01:01:41.320 --> 01:01:42.020
All right.

01:01:42.020 --> 01:01:46.900
Well, thanks again for being on the show and diving into the nuances and all the different

01:01:46.900 --> 01:01:48.340
names in the mocking world.

01:01:48.340 --> 01:01:48.900
It's been fun.

01:01:48.900 --> 01:01:49.180
Yeah.

01:01:49.180 --> 01:01:50.080
Thanks for having me.

01:01:50.080 --> 01:01:50.620
It was fun.

01:01:50.620 --> 01:01:50.960
Yeah.

01:01:50.960 --> 01:01:51.660
It's great to have you back.

01:01:51.660 --> 01:01:52.040
Bye.

01:01:52.040 --> 01:01:52.620
Bye.

01:01:53.940 --> 01:01:56.660
This has been another episode of Talk Python To Me.

01:01:56.660 --> 01:01:59.300
Our guest in this episode was Annalena Popkes.

01:01:59.300 --> 01:02:02.140
And it's been brought to you by Linode and Monday.com.

01:02:02.140 --> 01:02:07.040
Start your next Python project on Linode's state-of-the-art cloud service.

01:02:07.040 --> 01:02:09.820
Just visit talkpython.fm/Linode.

01:02:09.820 --> 01:02:11.360
L-I-N-O-D-E.

01:02:11.360 --> 01:02:14.660
You'll automatically get a $20 credit when you create a new account.

01:02:14.660 --> 01:02:19.280
Build your idea for an app and get it in front of hundreds of thousands of users on day one.

01:02:19.280 --> 01:02:25.280
Start building today at the Monday.com marketplace by visiting Monday.com slash Python.

01:02:25.280 --> 01:02:27.500
Want to level up your Python?

01:02:27.500 --> 01:02:32.320
If you're just getting started, try my Python Jumpstart by Building 10 Apps course.

01:02:32.320 --> 01:02:37.400
Or if you're looking for something more advanced, check out our new async course that digs into

01:02:37.400 --> 01:02:40.480
all the different types of async programming you can do in Python.

01:02:40.480 --> 01:02:44.420
And of course, if you're interested in more than one of these, be sure to check out our

01:02:44.420 --> 01:02:45.140
Everything Bundle.

01:02:45.140 --> 01:02:47.020
It's like a subscription that never expires.

01:02:47.420 --> 01:02:49.160
Be sure to subscribe to the show.

01:02:49.160 --> 01:02:51.660
Open your favorite podcatcher and search for Python.

01:02:51.660 --> 01:02:52.800
We should be right at the top.

01:02:52.800 --> 01:02:57.640
You can also find the iTunes feed at /itunes, the Google Play feed at /play,

01:02:57.640 --> 01:03:01.800
and the direct RSS feed at /rss on talkpython.fm.

01:03:01.800 --> 01:03:03.860
This is your host, Michael Kennedy.

01:03:03.860 --> 01:03:05.380
Thanks so much for listening.

01:03:05.380 --> 01:03:06.400
I really appreciate it.

01:03:06.400 --> 01:03:08.180
Now get out there and write some Python code.

01:03:08.180 --> 01:03:28.840
I'll see you next time.