This article assumes you already know your way around Python mocks and pytest. If you need a short recap, I find the following article extremely useful: What the mock? — A cheatsheet for mocking in Python.
Almost every experienced software developer knows that unit tests are important to ensure that the code performs the way it should, in addition it’s a way keep the code safe from regressions when new code is introduced.
Good unit tests are limited to testing a specific function, class or module. A best practice is to avoid external dependencies like databases or other classes which are not the focus when testing a narrow piece of code.
But what to do when your tested code has external dependencies? One common solution is to mock those dependencies.
A Programmer's Guide to Creating an Eclectic Bookshelf | Data Driven Investor
Every developer should have a bookshelf. The possible set of texts in his cabinet are myriad, but not every collection…
I bet anyone who has been doing Python unit tests which require mocking, has been frustrated with the time and effort it takes to set them up.
This article is meant to save you a lot of time and effort, by using a library I wrote — the Mock Generator.
Before I introduce my solution, let’s cover the basic structure of a mocked unit test:
- Arrange — Setup and prepare the various objects and prerequisites.
- Act — Invoke the tested code by calling the tested function for example.
- Assert — Verify the outcome. This can be the return value of the tested function and/or some side effects.
And now for a concrete example: the code below creates a zip with a single file inside it, containing a slightly modified content based on what the caller has sent:
What if I were to tell you, that you that most of this test can be auto generated?
In fact, the only thing in the body of this test which is not generated is line 6!
Let’s start by generating the assert part. The assert part is located after the arrange and act parts and assumes that they were already written and executed successfully. It’s the simplest part to generate and can save you a bunch of time. Here are some people struggling with the syntax on stack overflow here, here and here.
In the example above, lines 7 till 11 are the assert part. Some of them are not trivial to write, even for people who are experienced with mocks. Those lines verify that the right zip file was created, with the right file content written to it, they also check that the file was properly handled and closed at the end.
The procedure of generating the assert section is very simple, regardless of the complexity of the actual validations. For every mock object you have on your test, execute the following lines right after the act and replace them with the output:
That’s all there is to it!
After you understood how to generate the assert part, generating the arrange part should feel more natural to you. In many cases, this would be the first thing you would do, since it’s located at the start of the test.
The arrange part is about setting up the prerequisites for your test. This article’s focus is mocking, but you can obviously setup other stuff as well. The things you can mock in python are:
- Object attributes and entire objects
For the example above, we simply want to mock the zipfile module used in zip_writer. To do that, place this code at the beginning of your test:
from mock_autogen.pytest_mocker import PytestMocker
Once you execute those lines, replace them with their output — this is how lines 4 and 5 were generated.
Hooray! Your test is now complete and you have learned about some of the most important functionality of the Mock Generator. There are additional use cases and examples in the readme and the included tests.
To start using the utility just execute:
pip install mock-generator
If you have enjoyed the article or using the Mock Generator library, I’d love to hear from you. Even better, if you have any thoughts or feedback, let me know.
I’m accepting pull requests in GitHub :)