.. _`unittest.TestCase`: .. _`unittest`: unittest.TestCase Support ========================= ``pytest`` supports running Python ``unittest``-based tests out of the box. It's meant for leveraging existing ``unittest``-based test suites to use pytest as a test runner and also allow to incrementally adapt the test suite to take full advantage of pytest's features. To run an existing ``unittest``-style test suite using ``pytest``, type: .. code-block:: bash pytest tests pytest will automatically collect ``unittest.TestCase`` subclasses and their ``test`` methods in ``test_*.py`` or ``*_test.py`` files. Almost all ``unittest`` features are supported: * ``@unittest.skip`` style decorators; * ``setUp/tearDown``; * ``setUpClass/tearDownClass``; * ``setUpModule/tearDownModule``; .. _`load_tests protocol`: https://docs.python.org/3/library/unittest.html#load-tests-protocol .. _`subtests`: https://docs.python.org/3/library/unittest.html#distinguishing-test-iterations-using-subtests Up to this point pytest does not have support for the following features: * `load_tests protocol`_; * `subtests`_; Benefits out of the box ----------------------- By running your test suite with pytest you can make use of several features, in most cases without having to modify existing code: * Obtain :ref:`more informative tracebacks `; * :ref:`stdout and stderr ` capturing; * :ref:`Test selection options ` using ``-k`` and ``-m`` flags; * :ref:`maxfail`; * :ref:`--pdb ` command-line option for debugging on test failures (see :ref:`note ` below); * Distribute tests to multiple CPUs using the `pytest-xdist `_ plugin; * Use :ref:`plain assert-statements ` instead of ``self.assert*`` functions (`unittest2pytest `__ is immensely helpful in this); pytest features in ``unittest.TestCase`` subclasses --------------------------------------------------- The following pytest features work in ``unittest.TestCase`` subclasses: * :ref:`Marks `: :ref:`skip `, :ref:`skipif `, :ref:`xfail `; * :ref:`Auto-use fixtures `; The following pytest features **do not** work, and probably never will due to different design philosophies: * :ref:`Fixtures ` (except for ``autouse`` fixtures, see :ref:`below `); * :ref:`Parametrization `; * :ref:`Custom hooks `; Third party plugins may or may not work well, depending on the plugin and the test suite. .. _mixing-fixtures: Mixing pytest fixtures into ``unittest.TestCase`` subclasses using marks ------------------------------------------------------------------------ Running your unittest with ``pytest`` allows you to use its :ref:`fixture mechanism ` with ``unittest.TestCase`` style tests. Assuming you have at least skimmed the pytest fixture features, let's jump-start into an example that integrates a pytest ``db_class`` fixture, setting up a class-cached database object, and then reference it from a unittest-style test: .. code-block:: python # content of conftest.py # we define a fixture function below and it will be "used" by # referencing its name from tests import pytest @pytest.fixture(scope="class") def db_class(request): class DummyDB: pass # set a class attribute on the invoking test context request.cls.db = DummyDB() This defines a fixture function ``db_class`` which - if used - is called once for each test class and which sets the class-level ``db`` attribute to a ``DummyDB`` instance. The fixture function achieves this by receiving a special ``request`` object which gives access to :ref:`the requesting test context ` such as the ``cls`` attribute, denoting the class from which the fixture is used. This architecture de-couples fixture writing from actual test code and allows re-use of the fixture by a minimal reference, the fixture name. So let's write an actual ``unittest.TestCase`` class using our fixture definition: .. code-block:: python # content of test_unittest_db.py import unittest import pytest @pytest.mark.usefixtures("db_class") class MyTest(unittest.TestCase): def test_method1(self): assert hasattr(self, "db") assert 0, self.db # fail for demo purposes def test_method2(self): assert 0, self.db # fail for demo purposes The ``@pytest.mark.usefixtures("db_class")`` class-decorator makes sure that the pytest fixture function ``db_class`` is called once per class. Due to the deliberately failing assert statements, we can take a look at the ``self.db`` values in the traceback: .. code-block:: pytest $ pytest test_unittest_db.py =========================== test session starts ============================ platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y cachedir: $PYTHON_PREFIX/.pytest_cache rootdir: $REGENDOC_TMPDIR collected 2 items test_unittest_db.py FF [100%] ================================= FAILURES ================================= ___________________________ MyTest.test_method1 ____________________________ self = def test_method1(self): assert hasattr(self, "db") > assert 0, self.db # fail for demo purposes E AssertionError: .DummyDB object at 0xdeadbeef> E assert 0 test_unittest_db.py:10: AssertionError ___________________________ MyTest.test_method2 ____________________________ self = def test_method2(self): > assert 0, self.db # fail for demo purposes E AssertionError: .DummyDB object at 0xdeadbeef> E assert 0 test_unittest_db.py:13: AssertionError ========================= short test summary info ========================== FAILED test_unittest_db.py::MyTest::test_method1 - AssertionError: ` fixture to delegate the creation of a per-test temporary directory: .. code-block:: python # content of test_unittest_cleandir.py import pytest import unittest class MyTest(unittest.TestCase): @pytest.fixture(autouse=True) def initdir(self, tmpdir): tmpdir.chdir() # change to pytest-provided temporary directory tmpdir.join("samplefile.ini").write("# testdata") def test_method(self): with open("samplefile.ini") as f: s = f.read() assert "testdata" in s Due to the ``autouse`` flag the ``initdir`` fixture function will be used for all methods of the class where it is defined. This is a shortcut for using a ``@pytest.mark.usefixtures("initdir")`` marker on the class like in the previous example. Running this test module ...: .. code-block:: pytest $ pytest -q test_unittest_cleandir.py . [100%] 1 passed in 0.12s ... gives us one passed test because the ``initdir`` fixture function was executed ahead of the ``test_method``. .. note:: ``unittest.TestCase`` methods cannot directly receive fixture arguments as implementing that is likely to inflict on the ability to run general unittest.TestCase test suites. The above ``usefixtures`` and ``autouse`` examples should help to mix in pytest fixtures into unittest suites. You can also gradually move away from subclassing from ``unittest.TestCase`` to *plain asserts* and then start to benefit from the full pytest feature set step by step. .. _pdb-unittest-note: .. note:: Due to architectural differences between the two frameworks, setup and teardown for ``unittest``-based tests is performed during the ``call`` phase of testing instead of in ``pytest``'s standard ``setup`` and ``teardown`` stages. This can be important to understand in some situations, particularly when reasoning about errors. For example, if a ``unittest``-based suite exhibits errors during setup, ``pytest`` will report no errors during its ``setup`` phase and will instead raise the error during ``call``.