Testing in Python

Writing good unit tests in Python with ease — Part 3

Part 3: Testing workflow tips

This article series is aimed at people working in the public sector (like me), academics and students, people new to their careers in the private sector and anyone else for whom testing code is not yet second nature. When I refer to “tests” or “testing” in this article the context is constrained to unit and component/modular tests. My experience is mostly derived from building analytical pipelines in Python using pandas and pyspark and testing in pytest.

The series started as a written summary of a presentation given to the Office for National Statistics on Feb 26 2021. There is also an accompanying GitHub repo with some more advanced test parameterisation examples and other resources.

Here is a list of the articles in this series:

Here are the topics covered in this chapter:

Test Shells

If you can’t write your test straight away, write a test shell so you know to come back to it!

Snakes in the Grass 🐍

Mark your test shells using pytest.mark.skip(reason="test_shell") so that you can see where you have missing tests from pytest output at a glance.

Bash Bindings

Add these to your .bashrc to quickly cycle through your recent pytest commands in your bash history.

Start typing pytest then search using arrow keys

VS Code Shortcuts

I find the VS Code shortcuts extremely helpful for manipulating hard coded test data. They take a lot of the pain out of the process. I demo my favourite ones in this article.

VS Code Snippets

You can configure VS Code snippets for repeatable code patterns that occur in test scripts. Read more on snippets in the official docs and see some more of my own snippets defined in this JSON.

Creating a test shell class using VS Code snippets

Rules that you can break

There are some rules I feel comfortable breaking in my test scripts. These are:

  • Having max line length over 72 chars
  • Not obeying all docstring conventions
  • Not being DRY — at least not when starting out

As always, use your own judgement, and try to be consistent above all else.

Common pitfalls

It is probably worth mentioning a couple of common pitfalls that have caught me out a few times. If you can think of any more, please leave a comment and I’ll add to this list:

  • Grouping tests by class but forgetting to add self to the parameters.

The error message for this is probably going to cause a little confusion as it treats whatever parameter name is passed first instead as the class — self is just a conventional name for that parameter anyway, so pytest assumes you’ve just given it a different name when you probably forgot it altogether.
Here’s an example of what the error output looks like:

  • Forgetting to declare something as a fixture

Luckily the error message for this one is a bit more straightforward.

  • Doing too much — cut your functions down! Did I say this already? The number one thing that is going to slow down your testing process is trying to test functions that are doing too much logic in one go. Consider writing a component test to cover the main expected behaviour of your program, then refactor a large function into multiple smaller units.

Wrap Up

  • OK — now you’ve read the article, go write some tests.
  • Check out the accompanying GitHub repo for some additional resources.
  • If you liked something about this article or found it interesting, please leave a “clap”.
  • If you disagreed with something or have some additional tips to share then please leave a comment.

I hope these articles will be a good reference for you on your testing journey. Bon chance!

Building statistical pipelines for the ONS. Writing about testing and API design in pandas and PySpark. Enjoy cycling, learning Portuguese and playing piano!