Get startedGet started for free

Unit testing

1. Unit testing

Even well-documented, readable code isn't very useful if doesn't work correctly. That's where testing can come in handy.

2. Why testing?

With testing, you can confirm your code is working as intended. You probably already run some manual tests. Instead of writing these tests in the console, you could add much more value to your project by adding these to your test suite. A written test can be re-run after you make changes to check if there were any unexpected effects. Also, changes in dependencies can sometimes break your code. Automated tests can alert you problems like this and more.

3. Testing in Python

So how do we test in Python? We'll cover 2 easy to use options: doctest & pytest.

4. Using doctest

Thanks to writing informative docstrings with examples included you've already written tests that can be run with doctest! Let's look at an example with this square function. To use doctest we need to import it and run the testmod command to test our module's examples. When we run the tests we see that it failed. Looks like there was a typo in the docstring that was caught thanks to doctest. If there were no failed tests the output from testmod would be blank.

5. pytest structure

doctests are great for smaller examples, but you often can't cover every case you want to test in a docstring. For example, if your function returns a large pandas DataFrame this could be hard to include as a doctest. For larger cases, there's pytest. To use pytest, I recommend a tests directory at the same level as your package's directory.

6. pytest structure

Due to pytest's flexibility, there are other options. For example, if developing a larger package it might be useful to break out subpackage tests into their own folders.

7. Writing unit tests

Let's write some tests for our Document class. First, notice the test underscore prefix. pytest searches for tests by first looking for files that start or end with the word test, and then pytest runs all the functions in these files who's name follow the same pattern. Within our test method, we've then created an instance of document as our test case. Last, we run the actual test with the assert keyword. As long as the assertion is True, our test passes. When testing, it's also a good idea to test for the 'edge cases' that you can think of. For example, here we could test the expected attributes of a blank Document.

8. Writing unit tests

Note that when testing class objects, it's not wise to compare two objects with double equals. Here we create two identical Document objects and test equality. Our test shows the objects are not the same. Instead, to compare objects we can compare attributes as we see here.

9. Running pytest

To run our tests we head to the terminal in our work_dir directory, run the command "pytest", and wait for our output. We see that all of our tests passed and our code is running as expected.

10. Running pytest

If we just wanted to run the tests in one file our command might look like this and we'd only get the results for that file's tests.

11. Failing tests

So far all of our tests have passed. Let's look at some output of when things go wrong. In the output, we see exactly which test failed and even how it failed. This information can be a lifesaver when your projects grow and tracking down bugs becomes a more time-consuming process.

12. Let's Practice

Okay, we just covered the how-tos and benefits of doctest and pytest. Let's practice.