Ä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.