Python-Test mit Pytest. Plugins KAPITEL 5

Zurück Weiter


Pytest ist sofort leistungsstark genug und wird noch besser, wenn Sie eine Mischung aus Plugins hinzufügen. Die Pytest-Codebasis ist nach Einstellungen und Erweiterungen strukturiert, und es stehen Hooks zur Verfügung, die über Plugins geändert und verbessert werden können.



Die Beispiele in diesem Buch wurden mit Python 3.6 und pytest 3.2 geschrieben. pytest 3.2 unterstützt Python 2.6, 2.7 und Python 3.3+.


Der Quellcode für das Aufgabenprojekt sowie für alle in diesem Buch gezeigten Tests ist unter dem Link auf der Webseite des Buches unter pragprog.com verfügbar . Sie müssen den Quellcode nicht herunterladen, um den Testcode zu verstehen. Der Testcode wird in den Beispielen in einer praktischen Form dargestellt. Um jedoch die Aufgaben des Projekts zu verfolgen oder Testbeispiele anzupassen, um Ihr eigenes Projekt zu testen (Ihre Hände sind losgebunden!), Müssen Sie auf die Webseite des Buches gehen und die Arbeit herunterladen. Dort, auf der Webseite des Buches, gibt es einen Link für Errata- Nachrichten und ein Diskussionsforum .

Unter dem Spoiler befindet sich eine Liste der Artikel dieser Reihe.



Lass uns weiter gehen!


Es kann Sie überraschen, dass Sie bereits einige Plugins geschrieben haben, wenn Sie die vorherigen Kapitel in diesem Buch durchgearbeitet haben. Jedes Mal, wenn Sie Fixtures und / oder Hook-Funktionen in die Datei conftest.py der obersten Ebene des Projekts conftest.py , erstellen Sie ein lokales conftest Plugin. Es ist nur ein wenig zusätzliche Arbeit, diese conftest.py Dateien in installierbare Plugins zu konvertieren, die Sie zwischen Projekten, mit anderen Menschen oder mit der Welt teilen können.


Wir beginnen dieses Kapitel mit der Beantwortung der Frage, wo nach Plugins von Drittanbietern gesucht werden soll. Es sind nicht wenige Plugins verfügbar, daher besteht eine gute Chance, dass bereits jemand die Änderungen geschrieben hat, die Sie in pytest vornehmen pytest . Da wir Open Source-Plugins in Betracht ziehen, können Sie das Plugin, wenn es fast das tut, was Sie wollen, aber nicht ganz, entwickeln oder als Referenz verwenden, um Ihr eigenes Plugin zu erstellen. Obwohl es in diesem Kapitel darum geht, eigene Plugins zu erstellen, ist Anhang 3, das Sampler Pack- Plugin, auf Seite 163 enthalten, um Ihnen einen Eindruck davon zu geben, was möglich ist.


In diesem Kapitel erfahren Sie, wie Sie Plugins erstellen, und ich zeige Ihnen die richtige Richtung für das Testen, Verpacken und Verteilen. Das vollständige Thema der Python-Verpackung und -Distribution ist zu umfangreich und behauptet, ein eigenes Buch zu sein, sodass wir nicht alles behandeln werden. Sie erhalten jedoch genügend Informationen, um Plugins mit Ihrem Team austauschen zu können. Ich werde auch über einige einfache Möglichkeiten sprechen, Plugins mit PyPI-Unterstützung und dem geringsten Arbeitsaufwand zu erstellen.


Plugins suchen


Sie können Pytest-Plugins von Drittanbietern an mehreren Stellen finden. Die in Anhang 3, Plugin Sampler Pack, auf Seite 163 aufgeführten Plugins können von PyPI heruntergeladen werden. Dies ist jedoch nicht der einzige Ort, an dem Sie großartige Pytest-Plugins finden.


https://docs.pytest.org/en/latest/plugins.html


Die Hauptdokumentationsseite für pytest enthält eine Seite, auf der die Installation und Verwendung von pytest-Plugins beschrieben und einige gängige Plugins aufgelistet werden.


https://pypi.python.org


Der Python Package Index (PyPI) ist ein großartiger Ort, um viele Python-Pakete zu erhalten, aber auch ein großartiger Ort, um nach Pytest-Plugins zu suchen. Wenn Sie nach Pytest-Plugins suchen, geben Sie einfach "pytest", "pytest -" oder "-pytest" in das Suchfeld ein, da die meisten Pytest-Plugins entweder mit "pytest -" beginnen oder mit "-pytest" enden.


https://github.com/pytest-dev


In der pytest-dev-Gruppe auf GitHub wird der pytest-Quellcode gespeichert. Darüber hinaus finden Sie hier beliebte Pytest-Plugins, die langfristig vom Pytest-Kernel-Team unterstützt werden sollten.


Plugin Installation


Pytest-Plugins werden wie andere Python-Pakete mit pip installiert. Allerdings
Sie können pip auf verschiedene Arten verwenden, um Plugins zu installieren.


Von PyPI installieren


Da PyPI der Standardspeicherort für Pip ist, ist die Installation von Plugins von PyPI die einfachste Methode. Lassen Sie uns das pytest-cov Plugin installieren:


 $ pip install pytest-cov 

Die neueste stabile Version von PyPI wird installiert.


Installieren einer bestimmten Version von PyPI


Wenn Sie eine bestimmte Version des Plugins möchten, können Sie die Version nach == angeben:


 $ pip install pytest-cov==2.4.0 

Installation von einer .tar.gz- oder .whl-Datei


PyPI-Pakete werden als Zip-Dateien mit den Erweiterungen .tar.gz und / oder .whl . Sie werden oft als Teerkugeln und Räder bezeichnet. Wenn Sie Probleme haben, direkt mit PyPI zu arbeiten (was bei Firewalls und anderen Netzwerkkomplikationen auftreten kann), können Sie entweder .tar.gz oder .whl und von diesem oder jenem installieren.


Sie müssen nicht mit einem Tamburin auspacken oder tanzen. Zeigen Sie einfach mit Pip darauf:


 $ pip install pytest-cov-2.4.0.tar.gz # or $ pip install pytest_cov-2.4.0-py2.py3-none-any.whl 

Installation aus dem lokalen Verzeichnis


Sie können die Plugins für Plugins (und andere Python-Pakete) in einem lokalen oder freigegebenen Verzeichnis im .whl .tar.gz oder .whl und dieses anstelle von PyPI verwenden, um Plugins zu installieren:


 $ mkdir some_plugins $ cp pytest_cov-2.4.0-py2.py3-none-any.whl some_plugins/ $ pip install --no-index --find-links=./some_plugins/ pytest-cov 

--no-index weist pip keine Verbindung zu PyPI herzustellen. --find-links=./some_plugins/ weist pip an, im Verzeichnis some_plugins . Diese Methode ist besonders nützlich, wenn Sie sowohl Plugins von Drittanbietern als auch Ihre eigenen Plugins lokal gespeichert haben sowie wenn Sie neue virtuelle Umgebungen für die kontinuierliche Integration oder mit tox erstellen. (Wir werden in Kapitel 7 über Tox und kontinuierliche Integration sprechen, wobei Pytest mit anderen Tools verwendet wird, auf Seite 125.)


Bitte beachten Sie, dass Sie mit der Installationsmethode für das lokale Verzeichnis mehrere Versionen installieren und angeben können, welche Version Sie möchten, indem Sie == und die Versionsnummer hinzufügen:


 $ pip install --no-index --find-links=./some_plugins/ pytest-cov==2.4.0 

Installation aus dem Git-Repository


Sie können Plugins in diesem Fall direkt aus dem Git-Repository installieren. GitHub:


 $ pip install git+https://github.com/pytest-dev/pytest-cov 

Sie können auch das Versions-Tag angeben:


 $ pip install git+https://github.com/pytest-dev/pytest-cov@v2.4.0 

Oder Sie können einen Zweig angeben:


 $ pip install git+https://github.com/pytest-dev/pytest-cov@master 

Die Installation aus dem Git-Repository ist besonders nützlich, wenn Sie Ihre eigene Arbeit in Git speichern oder wenn die erforderliche Version des Plugins oder Plugins in PyPI fehlt.


Anmerkung des Übersetzers:

pip unterstützt die Installation von Git, Mercurial, Subversion und Bazaar und definiert den VCS-Typ mithilfe der URL-Präfixe: "git +", "hg +", "svn +", "bzr +".
Weitere Informationen finden Sie in der PyPI-Dokumentation .

Schreiben Sie Ihre eigenen Plugins


Viele Plugins von Drittanbietern enthalten viel Code. Dies ist einer der Gründe, warum wir sie verwenden, um uns Zeit zu sparen, all dies selbst zu entwickeln. Für Ihren spezifischen Code werden Sie jedoch zweifellos spezielle Vorrichtungen und Modifikationen finden, die Ihnen beim Testen helfen. Durch das Erstellen eines Plugins können Sie problemlos mehrere Geräte freigeben, die Sie für mehrere Projekte freigeben möchten. Sie können diese Änderungen mit mehreren Projekten - und möglicherweise mit dem Rest der Welt - teilen, indem Sie Ihre eigenen Plugins entwickeln und verteilen. Das ist ziemlich einfach. In diesem Abschnitt werden wir eine kleine Modifikation des Pytest-Verhaltens entwickeln, es als Plugin verpacken, testen und überlegen, wie es verteilt werden soll.


Plugins können Hook-Funktionen enthalten, die das Verhalten von pytest ändern. Da pytest so konzipiert wurde, dass Plugins das Verhalten von pytest geringfügig ändern können, stehen viele Hook-Funktionen zur Verfügung. Hooks für Pytest sind auf der Pytest-Dokumentationsseite aufgeführt . In unserem Beispiel erstellen wir ein Plugin, das das Erscheinungsbild des Teststatus ändert. Fügen Sie einen Befehlszeilenparameter hinzu, um dieses neue Verhalten zu aktivieren. Fügen Sie dem Ausgabekopf Text hinzu. Insbesondere werden wir alle Statusindikatoren FAILED (fehlgeschlagen) in "OPPORTUNITY (prospektiv) für Verbesserungen" ändern, F in O ändern und dem Header "Danke, dass Sie die Tests ausgeführt haben" hinzufügen. Dazu verwenden wir die Option --nice .


Um die Verhaltensänderungen von der Diskussion der Plugin-Mechanik zu trennen, werden wir Änderungen an conftest.py vornehmen, bevor wir es in ein weiterverteilbares Plugin verwandeln. Sie müssen keine Plugins auf diese Weise ausführen. Aber oft sind die Änderungen, die Sie in nur einem Projekt verwenden wollten, nützlich genug, um sie zu teilen und in ein Plugin umzuwandeln. Daher fügen wir der Datei conftest.py zunächst Funktionen hinzu, und nachdem alles in conftest.py funktioniert hat, verschieben wir den Code in das Paket.


Zurück zum Aufgabenprojekt. Im Abschnitt „Warten auf Ausnahmen“ auf Seite 30 haben wir mehrere Tests geschrieben, in denen überprüft wurde, ob Ausnahmen ausgelöst wurden, wenn jemand die API-Funktion falsch aufgerufen hat. Es sieht so aus, als hätten wir zumindest einige mögliche Fehlerzustände übersehen.


Hier noch ein paar Tests:


ch5 / a / task_proj / tests / func / test_api_exceptions.py

 """     API wrong.""" import pytest import tasks from tasks import Task @pytest.mark.usefixtures('tasks_db') class TestAdd(): """,   tasks.add().""" def test_missing_summary(self): """  ,  summary missing.""" with pytest.raises(ValueError): tasks.add(Task(owner='bob')) def test_done_not_bool(self): """  ,  done   bool.""" with pytest.raises(ValueError): tasks.add(Task(summary='summary', done='True')) 

Lassen Sie uns sie ausführen, um zu überprüfen, ob sie bestanden haben:


 $ cd /path/to/code/ch5/a/tasks_proj $ pytest ===================== test session starts ====================== collected 57 items tests/func/test_add.py ... tests/func/test_add_variety.py ............................ tests/func/test_add_variety2.py ............ tests/func/test_api_exceptions.py .F....... tests/func/test_unique_id.py . tests/unit/test_task.py .... =========================== FAILURES =========================== __________________ TestAdd.test_done_not_bool __________________ self = <func.test_api_exceptions.TestAdd object at 0x103a71a20> def test_done_not_bool(self): """Should raise an exception if done is not a bool.""" with pytest.raises(ValueError): > tasks.add(Task(summary='summary', done='True')) E Failed: DID NOT RAISE <class 'ValueError'> tests/func/test_api_exceptions.py:20: Failed ============= 1 failed, 56 passed in 0.28 seconds ============== 

Lassen Sie es uns noch einmal mit -v ausführen, um Details zu -v . Da Sie den Trace bereits gesehen haben, können Sie ihn durch Drücken von --tb=no .


Konzentrieren wir uns nun auf die neuen Tests mit -k TestAdd , was funktioniert, da es keine anderen Tests mit Namen gibt, die "TestAdd" enthalten.


Wir könnten "alles fallen lassen" und versuchen, diesen Test zu beheben (und wir werden es später tun), aber jetzt werden wir uns darauf konzentrieren, Fehler für Entwickler angenehmer zu machen.


Beginnen wir mit dem Hinzufügen einer Dankesnachricht zum Header, die Sie mit einem Pytest-Hook namens pytest_report_header() .


ch5 / b / task_proj / tests / conftest.py

 def pytest_report_header(): """    .""" return "Thanks for running the tests." 

Offensichtlich ist es ziemlich dumm, einen Dankesbrief zu schreiben. Die Möglichkeit, Informationen zum Header hinzuzufügen, kann jedoch erweitert werden. Sie können einen Benutzernamen hinzufügen, das verwendete Gerät und die zu testenden Versionen angeben. Im Allgemeinen kann alles, was Sie in eine Zeichenfolge konvertieren können, in den Titel des Tests eingefügt werden.


Dann ändern wir den Teststatusbericht, um F in O und FAILED in OPPORTUNITY for improvement zu ändern. Es gibt einen Hook, der diese Angelegenheit erlaubt: pytest_report_teststatus() :


ch5 / b / task_proj / tests / conftest.py

 def pytest_report_teststatus(report): """   .""" if report.when == 'call' and report.failed: return (report.outcome, 'O', 'OPPORTUNITY for improvement') 

Und jetzt haben wir genau die Lösung, nach der wir gesucht haben. Eine --verbose ohne das Flag --verbose zeigt O für Fehler an, --verbose Verbesserungen sind möglich:


 $ cd /path/to/code/ch5/b/tasks_proj/tests/func $ pytest --tb=no test_api_exceptions.py -k TestAdd ===================== test session starts ====================== Thanks for running the tests. collected 9 items test_api_exceptions.py .O ====================== 7 tests deselected ====================== ======= 1 failed, 1 passed, 7 deselected in 0.06 seconds ======= 

Mit dem Flag -v oder --verbose wäre besser:


 $ pytest -v --tb=no test_api_exceptions.py -k TestAdd ===================== test session starts ====================== Thanks for running the tests. collected 9 items test_api_exceptions.py::TestAdd::test_missing_summary PASSED test_api_exceptions.py::TestAdd::test_done_not_bool OPPORTUNITY for improvement ====================== 7 tests deselected ====================== ======= 1 failed, 1 passed, 7 deselected in 0.07 seconds ======= 

Die letzte Änderung, die wir vornehmen werden, besteht darin, den Befehlszeilenparameter --nice, damit Änderungen in unserem Status nur auftreten, wenn Sie --nice :


 def pytest_addoption(parser): """ nice    --nice.""" group = parser.getgroup('nice') group.addoption("--nice", action="store_true", help="nice: turn failures into opportunities") def pytest_report_header(): """    .""" if pytest.config.getoption('nice'): return "Thanks for running the tests." def pytest_report_teststatus(report): """   .""" if report.when == 'call': if report.failed and pytest.config.getoption('nice'): return (report.outcome, 'O', 'OPPORTUNITY for improvement') 

Es ist erwähnenswert, dass wir für dieses Plugin nur ein paar Hooks verwenden. Es gibt viele andere, die auf der Hauptdokumentationsseite von Pytest zu finden sind.


Jetzt können wir unser Plugin manuell testen, indem wir es in unserem Beispiel einfach ausführen. --nice ohne die Option --nice sicher, dass nur der Benutzername angezeigt wird:


 $ cd /path/to/code/ch5/c/tasks_proj/tests/func $ pytest --tb=no test_api_exceptions.py -k TestAdd ===================== test session starts ====================== collected 9 items test_api_exceptions.py .F ====================== 7 tests deselected ====================== ======= 1 failed, 1 passed, 7 deselected in 0.07 seconds ======= 

Jetzt mit --nice :


 $ pytest --nice --tb=no test_api_exceptions.py -k TestAdd ===================== test session starts ====================== Thanks for running the tests. collected 9 items test_api_exceptions.py .O ====================== 7 tests deselected ====================== ======= 1 failed, 1 passed, 7 deselected in 0.07 seconds ======= 

Jetzt mit --nice und --verbose :


 $ pytest -v --nice --tb=no test_api_exceptions.py -k TestAdd ===================== test session starts ====================== Thanks for running the tests. collected 9 items test_api_exceptions.py::TestAdd::test_missing_summary PASSED test_api_exceptions.py::TestAdd::test_done_not_bool OPPORTUNITY for improvement ====================== 7 tests deselected ====================== ======= 1 failed, 1 passed, 7 deselected in 0.06 seconds ======= 

Großartig! Alle Änderungen, die wir vornehmen wollten, wurden in etwa zehn Codezeilen für die Datei conftest.py . Als nächstes werden wir diesen Code in die Plugin-Struktur verschieben.


Erstellen eines installierbaren Plugins


Der Prozess des Teilens von Plugins mit anderen Benutzern ist klar definiert. Selbst wenn Sie niemals Ihr eigenes Plugin in PyPI einbinden, wird es Ihnen durch diesen Vorgang leichter fallen, den Code aus den Open Source-Plugins zu lesen, und Sie haben mehr Möglichkeiten zu bewerten, ob sie Ihnen helfen oder nicht.


Es wäre überflüssig, die Verpackung und Verteilung von Python-Paketen in diesem Buch vollständig zu behandeln, da dieses Thema an anderer Stelle gut dokumentiert ist. Hier und hier und hier auf Russisch. Es ist jedoch keine große Sache, vom lokalen Konfigurations-Plug-In, das wir im vorherigen Abschnitt erstellt haben, zu etwas zu wechseln, das mit pip installiert wurde. ,


Zuerst müssen wir ein neues Verzeichnis erstellen, um unseren Plugin-Code zu hosten. Es spielt keine Rolle, wie Sie es nennen, aber da wir ein Plugin für die nette Flagge erstellen, nennen wir es pytest-nice. Wir werden zwei Dateien in diesem neuen Verzeichnis haben: pytest_nice.py und setup.py. (Der Testkatalog wird im Abschnitt „Test-Plugins“ auf Seite 105 erläutert.)


 │ LICENSE │ pytest_nice.py │ setup.py │ └───tests │ conftest.py │ test_nice.py 

In pytest_nice.py wir den genauen Inhalt unserer conftest.py ein, der dieser Funktion zugeordnet war (und extrahieren ihn aus tasks_proj/tests/conftest.py ):


ch5 / pytest-nice / pytest_nice.py


 """  pytest-nice .""" import pytest def pytest_addoption(parser): """ nice    --nice.""" group = parser.getgroup('nice') group.addoption("--nice", action="store_true", help="nice: turn FAILED into OPPORTUNITY for improvement") def pytest_report_header(): """    .""" if pytest.config.getoption('nice'): return "Thanks for running the tests." def pytest_report_teststatus(report): """   .""" if report.when == 'call': if report.failed and pytest.config.getoption('nice'): return (report.outcome, 'O', 'OPPORTUNITY for improvement') 

In setup.py benötigen wir den minimalsten Aufruf von setup() :


ch5 / pytest-nice / setup.py

 """Setup  pytest-nice plugin.""" from setuptools import setup setup( name='pytest-nice', version='0.1.0', description=' Pytest,   FAILURE into OPPORTUNITY', url='https:////////', author=' ', author_email='your_email@somewhere.com', license='proprietary', py_modules=['pytest_nice'], install_requires=['pytest'], entry_points={'pytest11': ['nice = pytest_nice', ], }, ) 

Sie benötigen weitere Informationen in den Einstellungen, wenn Sie diese an ein breites Publikum oder im Internet verteilen möchten. Für ein kleines Team oder nur für sich selbst ist dies jedoch ausreichend.


Sie können einige andere Parameter für setup() angeben. und hier haben wir nur die erforderlichen Felder. Das Versionsfeld ist die Version dieses Plugins. Und es liegt ganz bei Ihnen, wenn Sie die Version aufrufen. Das URL-Feld ist erforderlich. Sie können es leer lassen, aber Sie erhalten eine Warnung. Die author_email author und author_email können durch maintainer und maintainer_email , aber eines dieser Paare sollte vorhanden sein. Das license ist ein kurzes Textfeld. Dies kann eine von vielen Open Source-Lizenzen sein, Ihr Name oder Unternehmen oder etwas, das für Sie geeignet ist. Der py_modules listet pytest_nice als unser einziges Modul für dieses Plugin auf. Obwohl dies eine Liste ist und Sie mehr als ein Modul einschließen können, würde ich, wenn ich mehr als ein Modul hätte, das Paket verwenden und alle Module in einem Verzeichnis ablegen.


Bisher sind alle setup() -Optionen Standard und werden von allen Python-Installationsprogrammen verwendet. Der Teil, der sich für Pytest-Plugins unterscheidet, ist der Parameter entry_points . Wir haben entry_points={'pytest11': ['nice = pytest_nice', ], },. Die Funktion entry_points ist Standard für setuptools , aber pytest11 ist die spezielle Kennung, nach der pytest sucht. In dieser Zeile teilen wir pytest mit, dass nice der Name unseres Plugins ist und pytest_nice Name des Moduls, in dem unser Plugin lebt. Wenn wir das Paket verwenden würden, wäre unser Eintrag hier:


Ich habe noch nicht über die Datei README.rst gesprochen. Eine Form von README ist eine Anforderung von Setuptools. Wenn Sie es verpassen, erhalten Sie Folgendes:


 ... warning: sdist: standard file not found: should have one of README, README.rst, README.txt ... 

Es ist sowieso eine gute Idee, README als Standardmethode für einige Projektinformationen beizubehalten. Folgendes habe ich in die Datei für pytest-nice eingefügt:


ch5 / pytest-nice / README.rst

 pytest-nice : A pytest plugin =============================   pytest     .  -------- -   ,     pytest. -  ``--nice`` , : -  ``F``  ``O`` -  ``-v``,  ``FAILURE``  ``OPPORTUNITY for improvement``  ------------ ,    Pytest    .tar.gz    PATH,  : :: $ pip install PATH/pytest-nice-0.1.0.tar.gz $ pip install --no-index --find-links PATH pytest-nice  ----- :: $ pytest --nice 

Es gibt viele Meinungen darüber, was in der README-Datei enthalten sein sollte. Dies ist eine stark beschnittene Version, aber sie funktioniert.


Plugins testen


Plugins sind Code, der wie jeder andere Code getestet werden muss. Das Testen von Änderungen an einem Testwerkzeug ist jedoch etwas komplizierter. Als wir den Plugin-Code im Abschnitt „Schreiben eigener Plugins“ auf Seite 98 entwickelten, überprüften wir ihn manuell anhand einer Beispieltestdatei, führten pytest damit aus und überprüften die Ausgabe, um sicherzustellen, dass sie korrekt war. Wir können dasselbe im automatischen Modus mit einem Plugin namens pytester , das mit pytest geliefert wird, aber standardmäßig deaktiviert ist.


In unserem Testverzeichnis befinden sich zwei Dateien für pytest-nice: conftest.py und test_nice.py . Um pytester , müssen wir pytester nur eine Zeile conftest.py :


ch5 / pytest-nice / tests / conftest.py

 """pytester is needed for testing plugins.""" pytest_plugins = 'pytester' 

Diese Zeile enthält das pytester Plugin. Wir werden ein Gerät namens testdir , das verfügbar wird, wenn der pytester .
Oft haben Tests für Plugins die Form, die wir manuell beschrieben haben:


  1. Erstellen Sie eine Beispieltestdatei.
  2. Führen Sie pytest mit oder ohne Parameter in dem Verzeichnis aus, das die Beispieldatei enthält.
  3. Überprüfen Sie die Ausgabe.
  4. Möglicherweise ist der Ergebniscode 0 für alle Durchgänge und 1 für einige Fehler.

Schauen wir uns ein Beispiel an:


ch5 / pytest-nice / tests / test_nice.py

 def test_pass_fail(testdir): #     Pytest testdir.makepyfile(""" def test_pass(): assert 1 == 1 def test_fail(): assert 1 == 2 """) #  pytest result = testdir.runpytest() # fnmatch_lines    result.stdout.fnmatch_lines([ '*.F', # .  Pass, F  Fail ]) # ,      '1'  testsuite assert result.ret == 1 

Fixture testdir erstellt automatisch ein temporäres Verzeichnis zum Hosten von Testdateien. Es verfügt über eine makepyfile() -Methode, mit der Sie den Inhalt einer Testdatei ablegen können. In diesem Fall erstellen wir zwei Tests: einen, der erfolgreich ist, und einen, der nicht erfolgreich ist .


Wir führen pytest für eine neue Testdatei mit testdir.runpytest() . Sie können Parameter übergeben, wenn Sie möchten. Der Rückgabewert kann später berücksichtigt werden und ist vom Typ RunResult .


Normalerweise schaue ich auf stdout und ret . , , , fnmatch_lines , , , , ret 0 1 . , fnmatch_lines , . . , , :


ch5/pytest-nice/tests/test_nice.py

 @pytest.fixture() def sample_test(testdir): testdir.makepyfile(""" def test_pass(): assert 1 == 1 def test_fail(): assert 1 == 2 """) return testdir 

, , sample_test , . :


ch5/pytest-nice/tests/test_nice.py

 def test_with_nice(sample_test): result = sample_test.runpytest('--nice') result.stdout.fnmatch_lines(['*.O', ]) # . for Pass, O for Fail assert result.ret == 1 def test_with_nice_verbose(sample_test): result = sample_test.runpytest('-v', '--nice') result.stdout.fnmatch_lines([ '*::test_fail OPPORTUNITY for improvement', ]) assert result.ret == 1 def test_not_nice_verbose(sample_test): result = sample_test.runpytest('-v') result.stdout.fnmatch_lines(['*::test_fail FAILED']) assert result.ret == 1 

. , :


ch5/pytest-nice/tests/test_nice.py

 def test_header(sample_test): result = sample_test.runpytest('--nice') result.stdout.fnmatch_lines(['Thanks for running the tests.']) def test_header_not_nice(sample_test): result = sample_test.runpytest() thanks_message = 'Thanks for running the tests.' assert thanks_message not in result.stdout.str() 

, , .


:


ch5/pytest-nice/tests/test_nice.py

 def test_help_message(testdir): result = testdir.runpytest('--help') # fnmatch_lines    result.stdout.fnmatch_lines([ 'nice:', '*--nice*nice: turn FAILED into OPPORTUNITY for improvement', ]) 

, , , .


pytest-nice , . .zip.gz , :


 $ cd /path/to/code/ch5/pytest-nice/ $ pip install . Processing /path/to/code/ch5/pytest-nice Requirement already satisfied: pytest in /path/to/venv/lib/python3.6/site-packages (from pytest-nice==0.1.0) Requirement already satisfied: py>=1.4.33 in /path/to/venv/lib/python3.6/site-packages (from pytest->pytest-nice==0.1.0) Requirement already satisfied: setuptools in /path/to/venv/lib/python3.6/site-packages (from pytest->pytest-nice==0.1.0) Building wheels for collected packages: pytest-nice Running setup.py bdist_wheel for pytest-nice ... done ... Successfully built pytest-nice Installing collected packages: pytest-nice Successfully installed pytest-nice-0.1.0 

, , :


 $ pytest -v ===================== test session starts ====================== plugins: nice-0.1.0 collected 7 items tests/test_nice.py::test_pass_fail PASSED tests/test_nice.py::test_with_nice PASSED tests/test_nice.py::test_with_nice_verbose PASSED tests/test_nice.py::test_not_nice_verbose PASSED tests/test_nice.py::test_header PASSED tests/test_nice.py::test_header_not_nice PASSED tests/test_nice.py::test_help_message PASSED =================== 7 passed in 0.34 seconds =================== 

. : , . .
 platform win32 -- Python 3.6.5, pytest-3.9.3, py-1.7.0, pluggy-0.8.0 -- c:\venv36\scripts\python.exe collected 7 items tests/test_nice.py::test_pass_fail FAILED [ 14%] tests/test_nice.py::test_with_nice OPPORTUNITY for improvement [ 28%] tests/test_nice.py::test_with_nice_verbose OPPORTUNITY for improvement [ 42%] tests/test_nice.py::test_not_nice_verbose FAILED [ 57%] tests/test_nice.py::test_header PASSED [ 71%] tests/test_nice.py::test_header_not_nice PASSED [ 85%] tests/test_nice.py::test_help_message PASSED [100%] ================================== FAILURES =================================== _______________________________ test_pass_fail ________________________________ 



  result.stdout.fnmatch_lines([ '*.F', # . for Pass, F for Fail ]) 


auf
  result.stdout.fnmatch_lines([ '*.F*', # . for Pass, F for Fail ]) 


* F

test_with_nice , test_with_nice_verbose , test_not_nice_verbose

pytest.
c
'test_with_nice.py .O [100%]'
.
,

RemovedInPytest4Warning: usage of Session.Class is deprecated, please use pytest.Class instead

!
 (venv36) c:\_BOOKS_\pytest_si\bopytest-code\code\ch5\pytest-nice>pytest -v ============================= test session starts ============================= platform win32 -- Python 3.6.5, pytest-3.9.3, py-1.7.0, pluggy-0.8.0 -- c:\venv36\scripts\python.exe cachedir: .pytest_cache rootdir: c:\_BOOKS_\pytest_si\bopytest-code\code\ch5\pytest-nice, inifile: plugins: nice-0.1.0 collected 7 items tests/test_nice.py::test_pass_fail PASSED [ 14%] tests/test_nice.py::test_with_nice PASSED [ 28%] tests/test_nice.py::test_with_nice_verbose PASSED [ 42%] tests/test_nice.py::test_not_nice_verbose PASSED [ 57%] tests/test_nice.py::test_header PASSED [ 71%] tests/test_nice.py::test_header_not_nice PASSED [ 85%] tests/test_nice.py::test_help_message PASSED [100%] ============================== warnings summary =============================== tests/test_nice.py::test_pass_fail c:\venv36\lib\site-packages\_pytest\compat.py:332: RemovedInPytest4Warning: usage of Session.Class is deprecated, please use pytest.Class instead return getattr(object, name, default) 

Hurra! . (pytest-nice), Python
pytest-:


 $ pip uninstall pytest-nice Uninstalling pytest-nice-0.1.0: Would remove: \path\to\venv\lib\site-packages\pytest_nice-0.1.0.dist-info\* ... Proceed (y/n)? y Successfully uninstalled pytest-nice-0.1.0 

— , pytest, PyPI.



, . , setup.py :


 $ cd /path/to/code/ch5/pytest-nice $ python setup.py sdist running sdist running egg_info creating pytest_nice.egg-info ... running check creating pytest-nice-0.1.0 ... creating dist Creating tar archive ... $ ls dist pytest-nice-0.1.0.tar.gz 

( , sdist source distribution — “ .”)


pytest-nice dist pytest-nice-0.1.0.tar.gz .


, , :


 $ pip install dist/pytest-nice-0.1.0.tar.gz Processing ./dist/pytest-nice-0.1.0.tar.gz ... Installing collected packages: pytest-nice Successfully installed pytest-nice-0.1.0 

.tar.gz , .



pip , , , , , , .tar.gz . , pytest-nice-0.1.0.tar.gz myplugins .


pytest-nice myplugins :


 $ pip install --no-index --find-links myplugins pytest-nice 

--no-index pip PyPI, , .
The --find-links myplugins tells PyPI to look in myplugins for packages to install. And of course, pytest-nice is what we want to install.
--find-links myplugins PyPI myplugins . , pytest-nice — , .


myplugins , , --upgrade :


 $ pip install --upgrade --no-index --find-links myplugins pytest-nice 

pip , --no-index --find-links myplugins .


PyPI


, , . , . , , , Python Packaging .


pytest, — cookiecutter-pytest-plugin :


 $ pip install cookiecutter $ cookiecutter https://github.com/pytest-dev/cookiecutter-pytest-plugin 

. , . ; , , . pytest, , .


Übungen


ch4/cache/test_slower.py autouse fixture, check_duration() . 4. .


  1. pytest-slower, , , « » . 102.
  2. , pytest-slower , .
  3. Schreiben Sie einen Testcode für das Plugin.
  4. Schauen Sie sich den Python Package Index an und suchen Sie nach "pytest-". Finden Sie ein Pytest-Plugin, das für Sie interessant aussieht.
  5. Installieren Sie das Plugin Ihrer Wahl und probieren Sie es bei den Tasks-Tests aus.

Was weiter


Sie haben bisher viele Male conftest.pyin diesem Buch verwendet. Es gibt auch Konfigurationsdateien, die sich beispielsweise auf die Ausführung von Pytests auswirken pytest.ini. Im nächsten Kapitel werden Sie sich mit den verschiedenen Konfigurationsdateien vertraut machen und herausfinden, was Sie tun können, um Ihnen das Leben beim Testen zu erleichtern.


Zurück Weiter

Source: https://habr.com/ru/post/de448794/


All Articles