Writing tests¶
We need to create unit tests for each module and test each function of the module.
An introductory example¶
Suppose we have a file called data_utils.py with two functions func1
and func2
, we should have a corresponding test file called test_data_utils.py with two corresponding test functions called test_func1
and test_func2
and data_utils.py imported.
- Note that we use
pytest
in our framework. Always import pytest at the top of the test file. - Please follow the naming convention: test_*.py for test file and test_* for test functions.
# content of mousestyles/mousestyles/utils.py
def func1():
return 3
def func2(x):
return x + 1
# content of mousestyles/mousestyles/tests/test_utils.py
from __future__ import (absolute_import,
division, print_function,
unicode_literals)
import pytest
from mousestyles.utils import func1, func2
def test_func1():
assert f() == 3
def test_func2():
assert func(3) == 4
Run all the tests for mousestyles¶
- For our
mousestyles
package, you can run all the tests withmake test
. Note thatmake test
always run makemake install
, thus you do not need to install beforehand. - Run
make test-fast
for quicker (but less foolproof) development. - If you want to look at the details, code for
make
command can be found here.
Pytest: basic usage¶
Installation:
pip install -U pytest
Run all files in the current directory and its subdirectories of the form test_*.py or *_test.py:
$ py.test
Or you may run one test file with or without “quiet” reporting mode:
$ py.test test_data_utils.py
$ py.test -q test_data_utils.py
Pytest: writing and reporting of assertions¶
pytest
allows you to use the standard python assert
for verifying
expectations and values. For example:
# contents of example1.py
def f():
return 3
def test_function():
assert f() == 4
If we run example1.py
using py.test example1.py
, it will fail because
the expected value is 4, but f
return 3.
We can also specify a message with the assertion like this:
assert a % 2 == 0, "value was odd, should be even"
In order to write assertions about raised exceptions, you can use pytest.raises as a context manager like this:
import pytest
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
def test_exception():
with pytest.raises(Exception):
x = 1 / 0
See Built-in Exceptions for more about raising errors.
If you need to have access to the actual exception info you may use:
def test_recursion_depth():
with pytest.raises(RuntimeError) as excinfo:
def f():
f()
f()
assert 'maximum recursion' in str(excinfo.value)
Pytest also support expected warnings, see pytest.warn
For more about assertions, see Assertions in pytest
What aspects of a function need to be tested:¶
- check if it returns correct type of object
- check if it returns correct dimension
- check if it returns the correct value, by
- prior knowledge
- different implementation: i.e. use R vs Python; use \(Var(X)\) vs. \(E(X^2) - E(X)^2\)
- theoretical derivation
- “regression”: if the function is improved (by speed, efficiency) while has same functionality, check the output is the same with older version.
- assert errors occured: i.e. when the function takes three arguements while we only give two, make sure the function will throw an error message
Reference¶
Most example above comes from Pytest documentation. See Pytest Documentation for more detail.