Python pytest
From wikinotes
Pytest produces more readable test failures, reduces boilerplate in tests, has a flexible builtin test-runner, and supports integration of pdb on failed tests.
Documentation
official docs https://docs.pytest.org/en/latest/ config format docs https://docs.pytest.org/en/latest/customize.html config option docs https://docs.pytest.org/en/latest/reference.html#configuration-options official api reference https://docs.pytest.org/en/latest/reference.html
Locations
{project}/pytest.ini
{project}/pyproject.toml
{project}/setup.cfg
pytest config locations (pytest recommends pyproject.toml) {project}/tests/test_*/test_*.py
default test structure {project}/tests/conftest.py
fixtures/helper functions available to tests in this directory, and those below it.
Configuration
configuration is performed in one of
pyproject.toml, pytest.ini, setup.cfg, tox.ini
.pyproject.toml
[tool.pytest.ini_options] markers = ["focus: selector for tests under development"] python_files = "*.py" testpaths = ["tests/unit", "tests/integration"]setup.cfg
# setup.cfg [aliases] # ``python setup.py test`` will run pytest # (requires 'pytest-runner') test=pytest [tool:pytest] python_files = *.py testpaths = tests norecursedirs = tests/integration/resources
Usage
pytest # run all tests pytest path/to/test.py # run tests within dir pytest path/to/dir # run tests within this dir and subdirs pytest -k "MyClass and not method" # runs tests containing string 'MyClass' and not tests containing string 'method' pytest path/to/test.py::test_func # run specific test pytest path/to/test.py::Test_Class::test_func # run specific class-method test pytest -k "MyClass::method[paramA-paramB]" # run a specific parametrized test pytest -m slow # run tests marked with decorator `@pytest.mark.slow`
Framework Usage
general
import pytest class Test_MyClass: def test_do_something(self): assert do_something() == 'success'expect exceptions
import pytest class Test_MyClass: def test_expectfail(self): with pytest.raises(RuntimeError, message='Expecting RuntimeError when ...'): do_something()parametrize tests
import pytest @pytest.mark.parametrize( 'a, b, result', [ (1,1,2), (2,1,3), (10,0,10), ]) def test_sum(a, b, result): assert (a+b) == resultfixtures (setup/teardown alternative)
fixtures are pre-built functions that you can use as parameters to your tests. Less code to read, less code to write.
Note that you can share fixtures with all of your tests, by adding them to the file
tests/conftest.py
.@pytest.fixture def myinstance(): instance = myclass.MyInstance() instance._attr = 'test value' instance._method = mock.Mock() return instance def test_myinstance(myinstance): assert myinstance.do_something() == 'success'conftest.py
You can load test helper libraries from conftest to expose functions.
# test/conftest.py import sys import os sys.path.append(os.path.join(os.path.dirname(__file__), 'helpers'))# test/helpers/database_helpers.py def mock_database_connection(): db = mock.MagicMock() cursor = mock.MagicMock() db.cursor = cursor return db# test/unit/test_something.py import database_helpers class TestSomething: def setup(self): self.db = database_helpers.mock_database_connection() def test_foo(self): # ...You can also define fixtures.
setup/teardown
class Test_YourClass(object): # ================================ # once-per-testclass instantiation # ================================ @classmethod def setup_class(cls): pass @classmethod def teardown_class(cls): pass # ==================== # once-per-method call # ==================== def setup_method(self, method): pass def teardown_method(self, method): passskipping tests
class TestFoo: def test_foo(self): pytest.skip('flaky test, needs fixing') @pytest.mark.skip(reason='flaky test, needs fixing') def test_bar(self): # test contents @pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python3.6 or higher") def test_baz(self): # test contentsfocusing specific tests
# ${PROJECT}/pytest.ini [pytest] markers = focus: being developed nowclass TestSomething: @pytest.mark.focus def test_something(self): assert 1 == 2pytest -m focus # run all focus tests pytest --markers # list all markers
Extensions
python pytest-cov check code-coverage