Pytest Plugins to Love ❤️. My top 5 and honorable 50 out of 600+... | by Martin Thoma | Towards Data Science

Pytest is extensible and has plenty of plugins. You don’t need to use any of them, but you might find some very useful. I love this because you have an easy time to get started with unit testing, while still finding amazing stuff when you’re more experienced 🤩
In this article, I’ll show you examples of plugins I use and the plugins I found while writing this article. You might want to cover the basics of unit testing first or refresh testing details like fixtures.
All plugins presented in this article can be installed via pip . Most of them are then already active. For example, when you install pytest-sugar via
pip install pytest-sugar
You can just execute pytest and the plugin will automatically work. Others need to be used more directly. For example, after installing pytest-timeout you need to specify the timeout parameter you want to use:
pytest --timeout=1
Don’t worry, I will explain those two plugins later 🙂
Searching on pypi.org for the trove classifier Framework :: Pytest , I found 668 packages. A stunning 1053 packages have “pytest” in the name. 461 packages have both, the name and the trove classifier.
I went through over 700 pytest-plugins for this article. I’ve jumped over plugins that consider themselves to be in planning, pre-alpha, or alpha stage. I’ve also skipped packages where I’ve seen a TODO in the readme or if the package had less than 10 stars on GitHub.
The packages I’ve found make pytest sparkle ✨, improve the speed 🏎, are specialized to specific packages, or just unique in their behavior ❄️
Last but not least, there are some plugins where I’m not sure if they are awesome or if they are a bad idea. Let’s jump right into it and have a look yourself!
Side note: Maybe you remember my side note on typo squatting? I found a fixable issue on PyPI while writing this article, hopefully improving security for the community🎉
The default output of pytest is already good, but some plugins make it amazing. pytest-sugar is one of those plugins❤
If those dots or checkmarks are too decent for you, givepytest-emoji and pytest-emoji-out a try 😃
The summary output now looks good, but the diffs between the expected value and the actual value can be improved. pytest-icdiff is a plugin I’ve only found while researching this article — and it was love at first sight 🥰❤
Very similar is pytest-clarity — be aware, that pytest-clarity is only active when you execute pytest -vv:
Once you're happy with the terminal output, you might think about getting reports in the browser. This could help once you have to have a look at many things, want to scroll and search. Then pytest-html is your friend. It generates reports like this one:
Now that we are happy with the output, we want to make it lightning fast!
Plugins can speed things up. For example, you can make pytest fail instantly with pytest-instafail instead of executing all remaining tests. For tests which might take a long time or even result in an infinite loop in case of errors, I use pytest-timeout ❤. That is especially helpful when you apply Mutation testing.
We also want to use our machine properly by using pytest-xdist . Install it, execute pytest -n autoand your tests run in parallel!pytest-parallelmight also be worth a shot.
The most extreme speedup is not to execute stuff you don’t need. pytest-picked executes tests that are related to unstaged files which can be way less than your complete test suite.
Going in a different direction, we want to make sure that the algorithms have some speed behavior. With pytest-benchmark , we can use the benchmark fixture to annotate parts of a test which we want to benchmark:
def test_argmax(benchmark):    assert benchmark(mpu.math.argmax, [1, 2, 3]) == 2
Running pytest then also gives this output, where you can see three functions to which I’ve added a benchmark. Two of them test a factorization function. It should not be a surprise that factorizing 3072 takes longer than factorizing 1024, but it is always astonishing to me how quickly the numbers grow. The argmax of 3 examples is super quick, but factorization just needs way more computation:
Some plugins are unique and don’t fit in any of the other categories:
pytest-cov : Get a test coverage report 😍 ❤ I like to generate both, an HTML report and an output to the terminal. In some settings, an XML report is also helpful.
pytest-socket : Make certain that you don’t query anything non-local. Very nice ❤
pytest-randomly and pytest-rng: If you use random.random , then the outcome depends on the random seed. This plugin changes the seed.
pytest-random-order : Execute the tests in a random order, to make sure you see when a test leaves the system in a different state.
pytest-lazy-fixtures : Use fixtures in @pytest.mark.parametrize .
pytest-freezegun : Freeze time! This is one I’ve also mentioned in my patching article.
pytest-leaks : Find resource leaks. This requires a debug-built of Python!
pytest-flake8 : Run flake8 via pytest. I did that for a long time, but when I learned how to use Continuous Integration pipelines more effectively, I stopped it. You can still execute flake8 directly.
pytest-mypy and pytest-mccabe: Same story as for flake8. By the way, type annotations are awesome! I like to have those static code analysis tools in a linter step within the CI pipeline.
pytest-deadfixtures : Point out which fixtures are not used or duplicated.
The following plugins are only interesting to you if you work with the applications for which they are written. They usually provide fixtures/mocks.
pytest-cookie : Supports testing of cookiecutter templates.
pytest-plt and pytest-mpl: Provides fixtures for matplotlib.
pytest-responses : Provides fixtures for requests .
pytest-asyncio : Use it when you develop async functions.
pytest-qt : GUI development via Qt / PySide / PySide2.
pytest-djangoapp / pytest-djangoqueries: Exposes tools for Django application developers to facilitate test authoring, including settings override, template tag testing, and user creation.
pytest-flask and pytest-flask-sqlalchemy : Provides fixtures for running tests in transactions using Flask-SQLAlchemy.
pytest-seleniumbase / pytest-sbase / pytest-selenium
moto : Mocks for boto3 — AWS stuff. I don’t exactly love this one, but it is for sure the best you can do when you want to test code that uses S3.
pytest-aws : Testing AWS resource configurations
pytest-localstack : Create AWS integration tests via a Localstack Docker container
The following plugins sounded cool for me when I first read about them, but for various reasons, I’m uncertain if they are really a good idea:
pytest-check : Allows multiple failures per test. At first, I loved the idea. Then I realized that this might lead to worse tests as the tests start to do many things. On the other hand, you might want to test a “workflow” once — so not a unit test, but an integration test or even an end-to-end test. But then you would also need intermediate results.
pytest-docker-tools and pytest-docker-compose: I would just build the Docker image and execute the stuff in it.
pytest-mock : Provides a mocker fixture which is a thin-wrapper around the patching API provided by the mock package. It reduces boilerplate code by making mock a fixture.
pytest-spec , pytest-pspec , and pytest-testdox modify the pytest output. They show what is tested. The tests should be written in such a way that they represent the software specification — so the test is against a part of the specification.
pytest-recording : It should record network interactions via VCR.py, but I didn’t get it to work.
pytest-dependency allows you to specify which tests need to succeed for others to be able to succeed. Unit tests should be independent and dependent code should be mocked...maybe. I’m not certain about that.
pytest is the tool of choice to run tests in Python. While it has reasonable defaults, it’s extensive plugin system lets you customize it to make it even better.
I love pytest-sugar and pytest-icdiff , because they make the output of pytest easier to read. pytest-cov generates line- and branch coverage and thus is a valuable tool to find spots that need better tests. The next step is to run the tests. You really don’t want to accidentally hit the production environment. This is wherepytest-socket comes into play. It just blocks everything and reports it to you. The other type of issue are long-running tests that are potentially in infinite loops.pytest-timeout kills those tests after the specified amount of time.
There are so many other plugins; many add fixtures for specific packages which are typically hard to test. You should now have a good idea of the many possibilities added by pytest plugins — use them!
In this series, we already had:
Part 1: The basics of Unit Testing in Python
Part 2: Patching, Mocks and Dependency Injection
Part 3: How to test Flask applications with Databases, Templates and Protected Pages
Part 4: tox and nox
Part 5: Structuring Unit Tests
Part 6: CI-Pipelines
Part 7: Property-based Testing
Part 8: Mutation Testing
Part 9: Static Code Analysis — Linters, Type Checking, and Code Complexity
Part 10: Pytest Plugins to Love
Let me know if you’re interested in other topics around testing with Python.