unittest is the batteries-included test module in the Python standard
library. Its API will be familiar to anyone who has used any of the
JUnit/nUnit/CppUnit series of tools.
Creating test cases is accomplished by subclassing unittest.TestCase.
import unittest
def fun(x):
return x + 1
class MyTest(unittest.TestCase):
def test(self):
self.assertEqual(fun(3), 4)
As of Python 2.7 unittest also includes its own test discovery mechanisms.
The doctest module searches for pieces of text that look like interactive
Python sessions in docstrings, and then executes those sessions to verify that
they work exactly as shown.
Doctests have a different use case than proper unit tests: they are usually less detailed and don’t catch special cases or obscure regression bugs. They are useful as an expressive documentation of the main use cases of a module and its components. However, doctests should run automatically each time the full test suite runs.
A simple doctest in a function:
def square(x):
"""Return the square of x.
>>> square(2)
4
>>> square(-2)
4
"""
return x * x
if __name__ == '__main__':
import doctest
doctest.testmod()
When running this module from the command line as in python module.py, the
doctests will run and complain if anything is not behaving as described in the
docstrings.
py.test is a no-boilerplate alternative to Python’s standard unittest module.
$ pip install pytest
Despite being a fully-featured and extensible test tool, it boasts a simple syntax. Creating a test suite is as easy as writing a module with a couple of functions:
# content of test_sample.py
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
and then running the py.test command:
$ py.test
=========================== test session starts ============================
platform darwin -- Python 2.7.1 -- pytest-2.2.1
collecting ... collected 1 items
test_sample.py F
================================= FAILURES =================================
_______________________________ test_answer ________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:5: AssertionError
========================= 1 failed in 0.02 seconds =========================
is far less work than would be required for the equivalent functionality with the unittest module!
Hypothesis is a library which lets you write tests that are parameterized by a source of examples. It then generates simple and comprehensible examples that make your tests fail, letting you find more bugs with less work.
$ pip install hypothesis
For example, testing lists of floats will try many examples, but report the minimal example of each bug (distinguished exception type and location):
@given(lists(floats(allow_nan=False, allow_infinity=False), min_size=1))
def test_mean(xs):
mean = sum(xs) / len(xs)
assert min(xs) <= mean(xs) <= max(xs)
Falsifying example: test_mean(
xs=[1.7976321109618856e+308, 6.102390043022755e+303]
)
Hypothesis is practical as well as very powerful and will often find bugs that escaped all other forms of testing. It integrates well with py.test, and has a strong focus on usability in both simple and advanced scenarios.
tox is a tool for automating test environment management and testing against multiple interpreter configurations.
$ pip install tox
tox allows you to configure complicated multi-parameter test matrices via a simple INI-style configuration file.
unittest2 is a backport of Python 2.7’s unittest module which has an improved API and better assertions over the one available in previous versions of Python.
If you’re using Python 2.6 or below, you can install it with pip:
$ pip install unittest2
You may want to import the module under the name unittest to make porting code to newer versions of the module easier in the future
import unittest2 as unittest
class MyTest(unittest.TestCase):
...
This way if you ever switch to a newer Python version and no longer need the unittest2 module, you can simply change the import in your test module without the need to change any other code.
unittest.mock is a library for testing in Python. As of Python 3.3, it is
available in the
standard library.
For older versions of Python:
$ pip install mock
It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used.
For example, you can monkey-patch a method:
from mock import MagicMock
thing = ProductionClass()
thing.method = MagicMock(return_value=3)
thing.method(3, 4, 5, key='value')
thing.method.assert_called_with(3, 4, 5, key='value')
To mock classes or objects in a module under test, use the patch decorator.
In the example below, an external search system is replaced with a mock that
always returns the same result (but only for the duration of the test).
def mock_search(self):
class MockSearchQuerySet(SearchQuerySet):
def __iter__(self):
return iter(["foo", "bar", "baz"])
return MockSearchQuerySet()
# SearchForm here refers to the imported class reference in myapp,
# not where the SearchForm class itself is imported from
@mock.patch('myapp.SearchForm.search', mock_search)
def test_new_watchlist_activities(self):
# get_search_results runs a search and iterates over the result
self.assertEqual(len(myapp.get_search_results(q="fish")), 3)
Mock has many other ways you can configure it and control its behavior.