9. Session 8 : Unit Tests#

Program testing can be used to show the presence of bugs, but never to show their absence!

Edsger Dijkstra

9.1. Background#

9.1.1. What#

Unit tests are typically automated tests written and run by software developers to ensure that a section of an application (known as the “unit”) meets its design and behaves as intended.

9.1.2. Why#

  • Regression. If I update my code, does it still reproduce the same results ?

  • Replication. Someone else can use your tests to check their implementation of your methods.

  • Repeatable. Provides verifiable guarantees to others who re-use your code.

9.1.3. How#

Use a Unit Test System. To be considered a Uint Test System, the system should offer

  • Automation. Run multiple tests in batches.

  • Independence. Each test should be completely independent from ay other.

  • Logging. Structured, human readable logs with summary information regarding the results.

  • Paramaters. Run the same tests multiple times with varying paramaters.

  • Portable. Developers, users and automated packaging systems should all be able to run the same tests with the same Unit Test System

9.1.4. When#

  • When code needs to be rerunnable (in an inhomogenous computing environment)

  • When code is reused by other developers

  • When code is regulary updated

  • When code is distributed e.g. via a package

9.2. An example - pytest#

pytest is a lightweight testing system for python. It is written in python and uses python constructs (e.g. assertions) for testing.

pytest can run tests defined locally or as part of a python package.

Individual test units are python functions.

9.2.1. Installing pytest#

pytest is available as a python package. It can be installed directly from PyPI. To install using pip

python -m pip install pytest

9.2.2. Using pytest#

pytest uses standard python assertions to capture errors during testing. Tests are organised as functions in files. By default, pytest loads the file and runs all of the functions it finds within the file.

9.3. Worked Example#

  1. Start pyenv

  2. Create a new python environment using venv

  3. Activate the environment

  4. Install pytest

  5. Create a python file calculatot.py with the following content

def add(a, b):
    return a + b
  1. Create a python file test_calculator.py with the following test

from calculator import add

def test_add():
    result = add(2, 3)
    assert result == 5
  1. Run the test

pytest

9.3.1. Key Concepts from Example 1#

  • Test files start must start with test_

  • Test functions must start with test_

  • Tests use standard python assert mechanism

9.4. Worked Example 2#

  1. Add a subtract function to calculator.py

  2. Add a test for the subtract function in calculator.py

Try the following commands to understand how finer control over which tests are run can be obtained using the pytest program

pytest
pytest test_calculator.py
pytest test_calculator.py::test_add
pytest -v

Imagine the file tests-1.py contains the following python

9.5. Types of test#

The basic test mechanism that pytest employs is the assert command from the python language. Consequently, all tests have to evaluate to True or False. When an assertion becomes a more complex epression, the expression should be abstracted into a function that returns True or False. Functions used for this purpose should also be stored in seperate files (so that they do not get tested).

Some standard tests are provided by pytest itself. For example, when comparing floating point values for equality it is necessary to do so within certian limits. The pytest function

9.5.1. Exercise#

Compare the following expression

(1/49)*49 == 1

with

from pytest import approx
(1/49)*49 == approx(1)

9.6. Paramaterised Tests#

9.6.1. Exercise#

  1. Add the following to your test_calculator.py file

import pytest

@pytest.mark.parametrize("a,b,expected", [
    (1, 2, 3),
    (5, 5, 10),
    (-1, 1, 0),
])

def test_add_multiple(a, b, expected):
    assert add(a, b) == expected
  1. Work out what it is doing.

  2. How is this useful ?

9.7. Exercise#

Write a function that returns a list. How would you use pytest to check that the contents of the lsit are as you expect them to be ?

9.8. Exercise#

As above, but for a dictionary.