Ändern der Standardmethode (Python) für die Testfindung

Pfade während der Testsammlung ignorieren

Sie können bestimmte Testverzeichnisse und -module während der Sammlung einfach ignorieren, indem Sie die Option --ignore=pfad auf der Kommandozeile übergeben. Pytest erlaubt mehrere --ignore-Optionen. Beispiel

tests/
|-- example
|   |-- test_example_01.py
|   |-- test_example_02.py
|   '-- test_example_03.py
|-- foobar
|   |-- test_foobar_01.py
|   |-- test_foobar_02.py
|   '-- test_foobar_03.py
'-- hello
    '-- world
        |-- test_world_01.py
        |-- test_world_02.py
        '-- test_world_03.py

Wenn Sie nun pytest mit --ignore=tests/foobar/test_foobar_03.py --ignore=tests/hello/ aufrufen, werden Sie sehen, dass pytest nur Testmodule sammelt, die nicht mit den angegebenen Mustern übereinstimmen.

=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 5 items

tests/example/test_example_01.py .                                   [ 20%]
tests/example/test_example_02.py .                                   [ 40%]
tests/example/test_example_03.py .                                   [ 60%]
tests/foobar/test_foobar_01.py .                                     [ 80%]
tests/foobar/test_foobar_02.py .                                     [100%]

========================= 5 passed in 0.02 seconds =========================

Die Option --ignore-glob erlaubt es, Testpfade basierend auf Unix-Shell-Wildcards zu ignorieren. Wenn Sie Testmodule ausschließen möchten, die mit _01.py enden, führen Sie pytest mit --ignore-glob='*_01.py' aus.

Tests während der Testsammlung deselektieren

Tests können einzeln während der Sammlung deselektiert werden, indem die Option --deselect=element übergeben wird. Angenommen, tests/foobar/test_foobar_01.py enthält test_a und test_b. Sie können alle Tests in tests/ ausführen, *außer* tests/foobar/test_foobar_01.py::test_a, indem Sie pytest mit --deselect tests/foobar/test_foobar_01.py::test_a aufrufen. Pytest erlaubt mehrere --deselect-Optionen.

Doppelte Pfade von der Kommandozeile beibehalten

Das Standardverhalten von pytest ist, doppelte Pfade, die von der Kommandozeile angegeben wurden, zu ignorieren. Beispiel

pytest path_a path_a

...
collected 1 item
...

Sammelt Tests nur einmal.

Um doppelte Tests zu sammeln, verwenden Sie die Option --keep-duplicates auf der Kommandozeile. Beispiel

pytest --keep-duplicates path_a path_a

...
collected 2 items
...

Ändern der Verzeichnisrekursion

Sie können die Option norecursedirs in einer Konfigurationsdatei festlegen.

# content of pytest.toml
[pytest]
norecursedirs = [".svn", "_build", "tmp*"]

Dies würde pytest anweisen, nicht in typische Subversion- oder Sphinx-Build-Verzeichnisse oder in Verzeichnisse mit dem Präfix tmp zu rekursieren.

Ändern von Namenskonventionen

Sie können andere Namenskonventionen konfigurieren, indem Sie python_files, python_classes und python_functions in Ihrer Konfigurationsdatei festlegen. Hier ist ein Beispiel:

# content of pytest.toml
# Example 1: have pytest look for "check" instead of "test"
[pytest]
python_files = ["check_*.py"]
python_classes = ["Check"]
python_functions = ["*_check"]

Dies würde pytest veranlassen, nach Tests in Dateien zu suchen, die dem Glob-Muster check_* .py entsprechen, nach Klassen, die mit Check beginnen, und nach Funktionen und Methoden, die *_check entsprechen. Wenn wir zum Beispiel haben:

# content of check_myapp.py
class CheckMyApp:
    def simple_check(self):
        pass

    def complex_check(self):
        pass

Die Testsammlung würde so aussehen:

$ pytest --collect-only
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.toml
collected 2 items

<Dir pythoncollection.rst-212>
  <Module check_myapp.py>
    <Class CheckMyApp>
      <Function simple_check>
      <Function complex_check>

======================== 2 tests collected in 0.12s ========================

Sie können nach mehreren Glob-Mustern suchen, indem Sie ein Leerzeichen zwischen den Mustern einfügen.

# content of pytest.toml
# Example 2: have pytest look for files with "test" and "example"
[pytest]
python_files = ["test_*.py", "example_*.py"]

Hinweis

Die Optionen python_functions und python_classes haben keinen Einfluss auf die unittest.TestCase-Testfindung, da Pytest die Ermittlung von Testfallmethoden an den Unittest-Code delegiert.

Kommandozeilenargumente als Python-Pakete interpretieren

Sie können die Option --pyargs verwenden, um pytest zu veranlassen, Argumente als Python-Paketnamen zu interpretieren, deren Dateisystempfade abzuleiten und dann den Test auszuführen. Wenn Sie beispielsweise unittest2 installiert haben, können Sie Folgendes eingeben:

pytest --pyargs unittest2.test.test_skipping -q

Dies würde das entsprechende Testmodul ausführen. Wie bei anderen Optionen können Sie durch eine Konfigurationsdatei und die Option addopts diese Änderung permanenter gestalten.

# content of pytest.toml
[pytest]
addopts = ["--pyargs"]

Nun wird eine einfache Ausführung von pytest NAME prüfen, ob NAME als importierbares Paket/Modul existiert, und es andernfalls als Dateisystempfad behandeln.

Herausfinden, was gesammelt wird

Sie können den Sammlungsbaum auch ohne Ausführung von Tests wie folgt einsehen:

. $ pytest --collect-only pythoncollection.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.toml
collected 3 items

<Dir pythoncollection.rst-212>
  <Dir CWD>
    <Module pythoncollection.py>
      <Function test_function>
      <Class TestClass>
        <Function test_method>
        <Function test_anothermethod>

======================== 3 tests collected in 0.12s ========================

Testsammlung anpassen

Sie können pytest leicht anweisen, Tests aus jeder Python-Datei zu entdecken.

# content of pytest.toml
[pytest]
python_files = ["*.py"]

Viele Projekte haben jedoch eine setup.py, die sie nicht importieren möchten. Darüber hinaus gibt es möglicherweise Dateien, die nur von einer bestimmten Python-Version importiert werden können. Für solche Fälle können Sie dynamisch zu ignorierende Dateien definieren, indem Sie sie in einer conftest.py-Datei auflisten.

# content of conftest.py
import sys

collect_ignore = ["setup.py"]
if sys.version_info[0] > 2:
    collect_ignore.append("pkg/module_py2.py")

und dann, wenn Sie eine Moduldatei wie diese haben:

# content of pkg/module_py2.py
def test_only_on_python2():
    try:
        assert 0
    except Exception, e:
        pass

und eine Dummy-Datei setup.py wie diese:

# content of setup.py
0 / 0  # will raise exception if imported

Wenn Sie mit einem Python 2-Interpreter ausführen, finden Sie den einen Test und lassen die Datei setup.py weg.

#$ pytest --collect-only
====== test session starts ======
platform linux2 -- Python 2.7.10, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 1 items
<Module 'pkg/module_py2.py'>
  <Function 'test_only_on_python2'>

====== 1 tests found in 0.04 seconds ======

Wenn Sie mit einem Python 3-Interpreter ausführen, werden sowohl der eine Test als auch die Datei setup.py weggelassen.

$ pytest --collect-only
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.toml
collected 0 items

======================= no tests collected in 0.12s ========================

Es ist auch möglich, Dateien basierend auf Unix-Shell-Wildcards zu ignorieren, indem Muster zu collect_ignore_glob hinzugefügt werden.

Das folgende Beispiel conftest.py ignoriert die Datei setup.py und zusätzlich alle Dateien, die mit *_py2.py enden, wenn sie mit einem Python 3-Interpreter ausgeführt werden.

# content of conftest.py
import sys

collect_ignore = ["setup.py"]
if sys.version_info[0] > 2:
    collect_ignore_glob = ["*_py2.py"]

Seit Pytest 2.6 können Benutzer verhindern, dass Pytest Klassen findet, die mit Test beginnen, indem sie ein boolesches Attribut __test__ auf False setzen.

# Will not be discovered as a test
class TestClass:
    __test__ = False

Hinweis

Wenn Sie mit abstrakten Testklassen arbeiten und das Attribut __test__ für Unterklassen nicht manuell setzen möchten, können Sie eine Mixin-Klasse verwenden, um dies automatisch zu handhaben. Zum Beispiel:

# Mixin to handle abstract test classes
class NotATest:
    def __init_subclass__(cls):
        cls.__test__ = NotATest not in cls.__bases__


# Abstract test class
class AbstractTest(NotATest):
    pass


# Subclass that will be collected as a test
class RealTest(AbstractTest):
    def test_example(self):
        assert 1 + 1 == 2

Dieser Ansatz stellt sicher, dass Unterklassen von abstrakten Testklassen automatisch gesammelt werden, ohne dass das Attribut __test__ explizit gesetzt werden muss.