Testing with Pytest¶
Pytest is arguably the most popular and widespread testing framework in the Python community. It is also compatible with Python’s unittest and doctest.
Generate XML report with pytest¶
To generate XML report, add the --junitxml=<report-path> or --junit-xml=<report-path> option.
Show test function docstring in report¶
# conftest.py
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
test_fn = item.obj
docstring = getattr(test_fn, '__doc__')
if docstring:
report.nodeid = docstring
# test_it.py
def test_ok():
"""This is my very important test."""
print("ok")
This will produce output similar to:
$ pytest -v
test_docstring_in_report.py::test_ok
..\..\..\This is my very important test. PASSED [100%]
Pytest built-in fixtures¶
List of pytest fixtures could be obtained by running pytest -q --fixtures.
Here are some interesting built-in fixtures:
capsysEnable text capturing of writes to
sys.stdoutandsys.stderr.Returns an instance of CaptureFixture to give access to captured
stdoutandstderr.The captured output is made available via
capsys.readouterr()method calls, which return a(out, err)namedtuple.outanderrwill betextobjects.Example:
def test_output(capsys): print("hello") captured = capsys.readouterr() assert captured.out == "hello\n"
capsysbinaryEnable bytes capturing of writes to
sys.stdoutandsys.stderr.The captured output is made available via
capsysbinary.readouterr()method calls, which return a(out, err)namedtuple.outanderrwill bebytesobjects.
capfdEnable text capturing of writes to file descriptors
1and2.The captured output is made available via
capfd.readouterr()method calls, which return a(out, err)namedtuple.outanderrwill betextobjects.
capfdbinaryEnable bytes capturing of writes to file descriptors
1and2.The captured output is made available via
capfd.readouterr()method calls, which return a(out, err)namedtuple.outanderrwill bebyteobjects.
pytestconfig[session scope] Session-scoped fixture that returns the pytest.config.Config object.Example:
def test_foo(pytestconfig): if pytestconfig.getoption("verbose") > 0: ...
monkeypatchA convenient fixture for monkey-patching.
The fixture provides these methods to modify objects, dictionaries or os.environ:
monkeypatch.setattr(obj, name, value, raising=True) monkeypatch.delattr(obj, name, raising=True) monkeypatch.setitem(mapping, name, value) monkeypatch.delitem(obj, name, raising=True) monkeypatch.setenv(name, value, prepend=False) monkeypatch.delenv(name, raising=True) monkeypatch.syspath_prepend(path) monkeypatch.chdir(path)
All modifications will be undone after the requesting test function or fixture has finished. The
raisingparameter determines if a KeyError or AttributeError will be raised if the set/deletion operation has no target.
requestSpecial fixture of class FixtureRequest providing information of the requesting test function.
tmpdirReturn a temporary directory path object which is unique to each test function invocation, created as a sub directory of the base temporary directory.
The returned object is a py.path.local path object.
tmp_pathReturn a temporary directory path object which is unique to each test function invocation, created as a sub directory of the base temporary directory.
The returned object is a
pathlib.Pathobject.Note
In python < 3.6 this is a pathlib2.Path.
Pytest plugins¶
pytest-bdd - Implements a subset of the Gherkin language to enable automating project requirements testing and to facilitate behavioral driven development.
pytest-cov - Produces coverage reports.
pytest-django - Provides a set of useful tools for testing Django applications and projects.
pytest-randomly - Randomly order tests with controlled seed.
pytest-reverse - Execute tests in reverse order.
pytest-splinter - Provides a set of fixtures to use splinter for browser testing with pytest
pytest-xdist - Adds test execution modes, e.g. multi-CPU and distributed.
Running doctest test cases¶
By default pytest is looking for test_*.txt files and if such a file is found, pytest executes the doctest tests defined in this file.
Pytest can also discover and execute doctest test cases from Python modules. For example if a function has docstring which contains doctest test cases, pytest can execute the tests.
def add(*args):
"""Add one or more numbers and return the result.
>>> add(3, 2)
5
>>> add(5, 4, 3, 2, 3, 4, 5)
26
"""
return sum(args)
To execute test cases from modules, specify the --doctest-modules option to pytest.
$ pytest --doctest-modules
============================== test session starts ==============================
platform win32 -- Python 3.8.1, pytest-6.1.0, py-1.9.0, pluggy-0.13.1
rootdir: C:\Sandbox\PoC\python-repl-cmd\src
plugins: cov-2.8.1, django-4.4.0, flask-0.14.0
collected 1 item
addition_doctest.py . [100%]
=============================== 1 passed in 0.04s ===============================
For further information refer to the pytest doctest integration documentation.
Running unittest test cases¶
Pytest can discover and execute unittest test cases:
import unittest
def add(*args):
return sum(args)
class TestAddition(unittest.TestCase):
def test_result_is_sum(self):
result = add(3, 2)
self.assertEqual(result, 5)
def test_add_many(self):
result = add(5, 4, 3, 2, 3, 4, 5)
self.assertEqual(result, 26)
Running the tests is as easy as:
$ pytest
============================== test session starts ==============================
platform win32 -- Python 3.8.1, pytest-6.1.0, py-1.9.0, pluggy-0.13.1
rootdir: C:\Sandbox\PoC\python-repl-cmd\src
plugins: cov-2.8.1, django-4.4.0, flask-0.14.0
collected 2 items
test_addition.py .. [100%]
=============================== 2 passed in 0.06s ===============================
This makes it very easy to migrate from unittest to pytest_ or to combine tests that use different frameworks.