We're sunsetting PodQuest on 2025-07-28. Thank you for your support!
Export Podcast Subscriptions
cover of episode pytest-mock : Mocking in pytest

pytest-mock : Mocking in pytest

2025/1/31
logo of podcast Test & Code

Test & Code

AI Chapters Transcript
Chapters
This chapter introduces the core concepts of mocking, patching, and monkey patching in software testing, explaining their purposes and relationships. It also briefly touches upon the differences between mocks, stubs, spies, and fakes.
  • Mocking involves replacing parts of a system with substitutes for testing purposes.
  • Patching is the act of replacing parts of a system with mocks.
  • Monkey patching is a simpler form of patching.
  • Mocks, stubs, spies, and fakes are related concepts with overlapping definitions.

Shownotes Transcript

The pytest mock plugin provides a fixture called Mocker. This fixture acts like a thin wrapper around the patching API provided by the mock package, which is now more commonly known as unit-test.mock. But hold on, what is mocking? What is mock? Why is the pytest plugin wrapping a unit-test submodule? And what extras does this plugin give us over straight unit-test mock?

But even what's the difference between a mock, a stub, and a spy, and a fake, and do I even need to care? We'll get into all of that in this episode. Welcome to Test & Code. This episode is brought to you by HelloPytest, the new fastest way to learn pytest, and by the PythonTest community. Find out more at courses.pythontest.com. By the way, pytestmock is sitting at number three on the top pytest plugin list.

Let's get a plan of attack to cover all of what we need to cover today. So let's cover what is mocking, patching, and monkey patching. What, if any, is the difference between a mock, a fake, a spy, and a stub? Why might we need these for testing? And then we'll get into some history of mock in Python and how mock became unit test dot mock.

Then we'll take a quick look at unit test.mock directly and specifically patch.object, patch.object with auto spec and using these as context managers.

There's a lot more in the mock package that we're not going to cover in this episode, but we're going to cover enough so that we can jump into PyTest mock. The PyTest mock plugin provides a fixture called mocker. One of the cool things it does is it cleans up after itself. There's also some convenience functions. So we're going to talk about mocker.patch, mocker.spy, and mocker.stub. And finally, is it really okay to use unit test.mock from PyTest?

Well, the answer is yes, but it seems weird until we look at all the history. Why do we mock? And what do all these words mean? There's a lot of new words here if you're new to this. Also, the entire concept might seem wacky. When we're testing software, there are times when it helps to replace a part of the system with something else. For instance,

Let's say we've got some part of the system that reaches out to an external system or has some side effect that we don't want to happen during testing. Like maybe sending an email, charging your credit card, or hitting a rate limited or slow API. We need to make sure that that stuff works also, but for the test in question, maybe we don't care.

If we really don't care, we can put a stub in place, an object or a function that can mimic the thing in question but doesn't do anything. So just mimic, it just like is in place so our code can call it, but it doesn't do anything. That would be like a stub. But we might want something like a stub, but also we want to make sure that the

the code calling this thing is calling it correctly. That would be a spy. So we could like reach in, look, ask the spy, Hey, did you get called the right way? Or maybe we want the action to happen, but we can't really test the outcome. So we still want to make sure the thing is called right. And we want it to actually do the thing, but we want to like find out how it was called. We also might want a fake thing that kind of responds correctly.

as if the action happened, like returning data, but it doesn't actually do anything. So maybe it returns pre-canned responses or something. Those are all kind of lumped into the mock, spy, stub, all of that stuff. And there's a lot of different definitions and they sort of overlap.

The term patch also is sometimes we talk about like the thing that we're replacing in there as a patch, but also the term patch is used to describe how we're updating the system. So we patch a part of the system with a fake or a spy or a stub, or we patch it with a patch.

there's also monkey patching it's really the same thing as patching but sometimes it's simpler for instance with the pi test pi test has a built-in fixture called monkey patch that doesn't do all the stuff that unit test mock does but it does a lot so all of these things all these concepts are related and that's why i'm really grateful for to michael ford

when he originally implemented the mock library that he didn't distinguish between all of these he just called all of these things mocks so mock objects in unit test.mock are all of these they're spies they're fakes they're stubs you can do all of that stuff with unit test mock objects

So let's get into the mock library. The mock library had some life on its own before it became unit test.mock as part of the Python standard library in Python 3.3. The library is actually quite large and it does a lot.

But when I use unit test.mock directly, I normally just use patch.object with or without auto spec. And I use that with a with block and that returns, so it's a context manager. I use it as a context manager usually. And it returns a mock object that you can make it, you can set it up to behave just as you want as a spy or return, you can modify what a function is going to return or whatever.

And then after the with block, the whole thing is unmarked. So whatever you patched, it gets cleaned up after the with block, which is awesome. What about this term auto spec? An auto spec object or a function is just an object or a function that you when you create it, you give it the thing you want patch and patch object to copy. And it copies the exact interface of the thing that you're patching. So

So the specification is automatic, thus auto spec. That's a little confusing to me at least. But if I only want to like mock a couple things or one or two things, I'll often pull in just unit test dot mock with patch object used as a context manager. But now let's turn to PyTest mock because it's kind of awesome. PyTest mock claims to be a thin wrapper around unit test dot mock.

And it is, but it's also more, and I like it. You see, it's simpler to use, partly because the interface is restricted. Well, it's not really restricted, but it seems restricted, and that's nice. The way you use it is you include a mocker fixture in your test param list, just like you use any other fixture. And then with that mocker fixture, you can call patch, patch object, spy, or stub. Patch and patch object act together.

just like mock.patch and mock.patchObject. So usually I'm using patch.object. Don't try to use them as context managers. That's not supported by pytestmock. What you do instead is you just, once you patch something, it gets cleaned up automatically at the end of the test function. Because Mocker is a fixture, it can have a teardown and it cleans up. That's so cool.

What about these other things called spies and stubs? Well, in the PyTest mock nomenclature,

A mocker, if you call mocker.spy, you get a patch object that returns something that behaves just like the original, so it has the full behavior, but you can ask it questions about how it was called. So in PyTest mock terminology, mocker.spy means do the thing, but also I'm going to ask you about it. And then mocker stub is the other one. So mocker.stub returns something that does not behave like the original, but

But you can still ask it how it was called. So that would be more like just a normal mock object. And then each of these, all of these, like patch object, marker spy, and marker stub, you can pass in auto spec equals true to those too. And it works just like unit test.mock. The auto spec will copy the specification of the thing that you're mocking. That's because it really is a thin wrapper around

unit-test.mock and the things it returns are objects from the unit-test.mock library. And you still have access to the full power of unit-test.mock. However,

This limited interface into how to use mocking is very refreshing. And I think that is pretty much what I always need. I need to patch an object and or I might need to use an object as is, but spy on it. Or I might want to stub the whole thing and not not have the normal behavior. So those are really the things that I would I would want from mocking normally. So I really like that the plugin focuses on that.

I did mention this earlier, but I want to mention it again. There is monkey patch. PyTest has a built-in fixture called monkey patch. It might do what you need it to do when you're looking to mock something. So check that out first. Check out the interface to monkey patch and what you can do. It might be enough. You might not need to reach for unitest.mock or pytestmock.

Probably should do an episode on that directly, even though it's not a plugin. I'm going to put links to all this in the show notes. We're going to have a link to the top PyTest plugin list.

the PyTest mock documentation, Unit Test mock documentation. And then I did an entire episode with Michael Ford on the podcast a while ago. I'm going to put a link to that. But I also think I might like re-release that so that you can, even if you don't want to go back in the back history, you might have it just show up in your feed because it's a really great episode to talk about mocking. And then reference to monkey patch so you can look up what PyTest monkey patch is like.

And that's all for today. Thanks. Thank you for listening. And thank you to everyone who has supported the show through purchases of the courses, both Hello PyTest, the new fastest way to learn PyTest, and the complete PyTest course, if you'd like to really become an expert at PyTest. Both are available at courses.pythontest.com. And there you can also join the Python test community. That's all for now. Now go out and test something.