10. Unit testing (python)#
“Program testing can be used to show the presence of bugs, but never to show their absence!”
Edsger Dijkstra
10.1. Background#
10.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.
10.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 reuse your code.
10.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
10.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
10.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 pyhton package.
Individual test units are python functions.
10.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
10.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.
10.2.2.1. Example test file#
Imagine the file tests-1.py contains the following python
def test_1() :
assert 5 == 5
def test_2() :
assert 4 == 5
Each function is a test. The tests are run using (assuming the file tests0-1.py is in the current directory)
pytest tests-1.py
10.2.2.2. Exercise#
Install pytest
create the tests-1.py file
run the tests in tests-1.py using pytest
Note, the functions run by pytest are not usually the functions that require testing. They are functions that call one or more of the functions being tested. This approach immediately provides for independence, paramaters, and automation using only features of the language in which the code being tests is written. Simples !!
By default, pytest tests all of the functions it finds in the test file. The functions you want to test should therefore be in seperate files and should be accessed by importing them into the test file. For example.
from mypackage import myfunction
def test_1() :
for i in range(10) :
assert myfunction(i) == 2 * i
10.2.2.3. Exercise#
Use the code in Appendix 1 as the basis for a test of the choH function.
10.2.3. 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
10.2.3.1. Exercise#
Compare the following expression
(1/49)*49 == 1
with
from pytest import approx
(1/49)*49 == approx(1)
10.2.3.2. Exercise#
Add a test which checks the minimum value of the output of choH is correct.
10.2.3.3. Exercise#
Add a test which checks the location of the minimum value of the output of choH is correct.
10.3. pytest and python packages#
Once you have a collection of tests you can include them in a package. It is common to create a directory under the main module directory called tests and include your tests in this directory (module). For users of your package to be able to run your tests, this directory should itself define a module in the package.
10.3.1. Exercise#
What do you need to add to the tests directory to make it a module in the package ?
10.3.2. Exercise#
Are there any other changes in your package necessary for users to run your tests ?
10.3.2.1. Exercise#
Push your new version of the choH package to github.
10.3.3. Running package tests using pytest#
10.3.3.1. Exercise#
Uninstall your old version of the choH and install the latest version from your github repository.
You should now be able to run pytest on the installed package using
pytest --pyargs choH.tests.runtests
Notice how pytest uses the same format as import to locate the tests in the package.