A Simple Introduction to Automating Unit Tests in Python
By: Abdul Rahman
Tags: Software Development, Testing, Software Engineering, Programming, Python

In 1999 a navigation error saw NASA’s Mars Climate Orbiter crashing into the red planet’s atmosphere, and with it burnt years of painstaking work and millions of dollars spent building it. What was the cause? The commands sent to the spacecraft used English units instead of metric units. Mathematical and technical errors like these could result in catastrophic failures, some even ending in serious casualties. Hence the case for testing being an indispensable part of software development.

“Unit Testing” is when you test one unit of your software independent of any other units. Typically in Object Oriented Development (OOD) this unit is a class. But, what is testing? In simple terms, testing means checking the output of your code against a set of pre-defined, correct expected output/results. You need to have test data — both input and expected output/results — before you start testing. I said “output/results” because sometimes your code doesn’t output data, rather it modifies some data in your software.

Now, manually testing your code i.e. running it yourself, entering input via a user interface and visually examining the results is gruellingly boring and no doubt cumbersome. Plus, this way of testing isn’t easily scalable or repeatable. Instead you could write a tester class that simply calls all your functions and compares the results with a set of pre-defined ones. However, the problem with this method is that the functions you are testing could call other functions which may run some code elsewhere and so on. This could really mess up the working of your software or even corrupt any valuable data you might have on your database. Remember Unit Testing is all about testing one thing at a time. The solution to this is writing isolated, automated tests with the help of tools like pytest, unittest and nose2.

Since the goal of this tutorial is not to delve deep into the intricacies of software testing, let’s head straight into writing some automated tests in Python. We will be using the unittest Python library to write tests and nose2 to run them.

Prerequisites: Make sure you have Python 3 installed on your PC. You will also need to install the following libraries: unittest, mock, tinydb and nose2. You can install these using pip.

WHAT ARE WE TESTING?

We have here a Python class called “Customer”. The class has some basic functions that allow us to add and retrieve customer data. We are using a very basic python database called tinydb to store the data.

tinydb stores data in a JSON file in the same directory as the python code. You can instantiate the Customer class by providing a customer ID. But when you add a customer you have to provide the customer name, email and type and it will assume the customer ID given during instantiation. A customer is only added if they don’t already exist in the database and only loaded if they do exist.

HAVING A TEST PLAN

It is very handy to have a test plan before you start writing tests. You should think of:

1- What your code does.

This includes (but is not limited to):

an overview of what can be achieved from the program

what functions the program has

what input, if any, do the functions take

what results can be expected from the functions.

2- Good and bad case scenarios

When you think of the expected results you need to take into account both successful execution of your functionalities and anomalies that could occur.

Eg: Adding an already existing customer should result in a warning.

3- What does not require testing

Your program may include code where you invoke functions already tested. You don’t want to test them again. There could also be functions from external packages that you don’t have to bother about.

Eg: The tinydb insert function.

4- Of course, the tests themselves

Here we will need to write tests for the following functionalities: