Automatisiertes Testen mit Pytest

Eine Übersetzung des Artikels wurde speziell für Studenten des Python QA Engineer- Kurses erstellt.




Wir leben in einer Zeit, in der Software sehr schnell auf den Markt kommt. Aus diesem Grund wird der Entwicklungsprozess sehr stressig. Hohe Software-Implementierungsraten und schnelle Lieferung scheinen ein guter Teil des Geschäftsmodells zu sein, aber hier stellt sich die Frage, wie man Software in der richtigen Qualität liefert.

Warum brauchen wir automatisierte Tests?


Automatisierte Tests bieten viele Vorteile. Hier sind drei Hauptvorteile:
Wiederverwendung: Es ist nicht erforderlich, jedes Mal neue Skripte zu schreiben, selbst wenn eine neue Version des Betriebssystems veröffentlicht wird, es sei denn, dies ist dringend erforderlich.
Zuverlässigkeit: Menschen neigen dazu, Fehler zu machen, und Autos machen sie weniger wahrscheinlich. Und sie arbeiten schneller, wenn wiederholte Schritte / Tests ausgeführt werden, die kontinuierlich durchgeführt werden müssen.
Rund um die Uhr arbeiten: Sie können jederzeit mit dem Testen beginnen, auch aus der Ferne. Wenn Sie nachts mit dem Testen beginnen, läuft es auch, während Sie schlafen.

Entwickeltes Pytest-Test-Tool mit vollem Funktionsumfang in Python


Derzeit gibt es viele Frameworks und Tools zum Testen. Es gibt verschiedene Arten von Frameworks, z. B. datengesteuert, schlüsselwortgesteuert, hybrid, BDD usw. Sie können diejenige auswählen, die Ihren Anforderungen am besten entspricht.

Ich muss sagen, dass Python und pytest in dieser Angelegenheit eine große Nische einnehmen. Python und seine verwandten Tools sind weit verbreitet, wahrscheinlich weil sie im Vergleich zu anderen Sprachen für Leute mit geringer Programmiererfahrung zugänglicher sind.

Das pytest Framework erleichtert das Schreiben kleiner Tests, kann aber auch für anspruchsvolle Funktionstests von Anwendungen und Bibliotheken skaliert werden.

Einige Hauptmerkmale von pytest :

  • Automatische Erkennung von Testmodulen und Funktionen;
  • Effektive CLI zur Verbesserung der Kontrolle darüber, was Sie ausführen oder überspringen möchten.
  • Großes Drittanbieter-Ökosystem von Plugins;
  • Vorrichtungen - verschiedene Typen, verschiedene Anwendungen;
  • Arbeiten Sie mit dem traditionellen Unit-Testing-Framework.

Automatische und konfigurierbare Testerkennung


Standardmäßig erwartet pytest dass Tests in den Python-Modulen gefunden werden, deren Namen mit test_ beginnen oder mit _test.py . Standardmäßig werden die Namen der Testfunktionen mit dem Präfix test_ . Dieses pytest kann jedoch geändert werden, indem Sie einer der pytest Konfigurationsdateien Ihre eigene Konfiguration hinzufügen.

 # content of pytest.ini # Example 1: have pytest look for "check" instead of "test" # can also be defined in tox.ini or setup.cfg file, although the section # name in setup.cfg files should be "tool:pytest" [pytest] python_files = check_*.py python_classes = Check python_functions = *_check 

Schauen wir uns eine sehr einfache Testfunktion an:

 class CheckClass(object): def one_check(self): x = "this" assert 'h' in x def two_check(self): x = "hello" assert hasattr(x, 'check') 

Hast du etwas bemerkt? Es gibt kein assertEqual oder assertDictEqual , nur eine zugängliche und verständliche assertDictEqual . Es ist nicht erforderlich, diese Funktionen zu importieren, um einfach zwei Objekte zu vergleichen. Assert ist das, was Python bereits hat und es besteht keine Notwendigkeit, das Rad neu zu erfinden.

Vorlagencode? Mach dir keine Sorgen, Geräte eilen zur Rettung!


Sehen Sie sich die Testfunktionen an, mit denen die grundlegenden Vorgänge im Wallet-Programm getestet werden:

 // test_wallet.py from wallet import Wallet def test_default_initial_amount(): wallet = Wallet() assert wallet.balance == 0 wallet.close() def test_setting_initial_amount(): wallet = Wallet(initial_amount=100) assert wallet.balance == 100 wallet.close() def test_wallet_add_cash(): wallet = Wallet(initial_amount=10) wallet.add_cash(amount=90) assert wallet.balance == 100 wallet.close() def test_wallet_spend_cash(): wallet = Wallet(initial_amount=20) wallet.spend_cash(amount=10) assert wallet.balance == 10 wallet.close() 

Ähm, interessant! Hast du es bemerkt? Es gibt eine Menge Code für Boilerplates. Bemerkenswert ist auch, dass dieser Test nicht nur den Funktionsteil testet, wallet.close() beispielsweise eine Brieftasche erstellt und mit wallet.close() .

Schauen wir uns nun an, wie Sie mit Hilfe von Pytest- pytest Boilerplate-Code loswerden können.

 import pytest from _pytest.fixtures import SubRequest from wallet import Wallet #==================== fixtures @pytest.fixture def wallet(request: SubRequest): param = getattr(request, 'param', None) if param: prepared_wallet = Wallet(initial_amount=param[0]) else: prepared_wallet = Wallet() yield prepared_wallet prepared_wallet.close() #==================== tests def test_default_initial_amount(wallet): assert wallet.balance == 0 @pytest.mark.parametrize('wallet', [(100,)], indirect=True) def test_setting_initial_amount(wallet): assert wallet.balance == 100 @pytest.mark.parametrize('wallet', [(10,)], indirect=True) def test_wallet_add_cash(wallet): wallet.add_cash(amount=90) assert wallet.balance == 100 @pytest.mark.parametrize('wallet', [(20,)], indirect=True) def test_wallet_spend_cash(wallet): wallet.spend_cash(amount=10) assert wallet.balance == 10 

Schön, nicht wahr? Testfunktionen sind jetzt kompakt und tun genau das, was sie tun sollen. Die Brieftasche wird mithilfe der wallet konfiguriert, installiert und geschlossen. Fixtures helfen nicht nur beim Schreiben von wiederverwendbarem Code, sondern erweitern auch das Konzept der Datenfreigabe. Wenn Sie genau hinschauen, ist der Betrag in der wallet Teil der Testdaten, die extern von der Testlogik bereitgestellt werden und nicht fest in der Funktion verankert sind.

 @pytest.mark.parametrize('wallet', [(10,)], indirect=True) 

In einer stärker kontrollierten Umgebung befindet sich möglicherweise eine Datei mit Testdaten, z. B. test-data.ini in Ihrem Repository oder Ihrer Shell, die diese lesen kann, während Ihre Testfunktion verschiedene Shells aufrufen kann, um Testdaten zu lesen.

Es wird jedoch empfohlen, alle Ihre conftest.py in einer speziellen conftest.py Datei conftest.py . Dies ist eine spezielle Datei in pytest, mit der der Test globale Fixtures erkennen kann.

Ich habe aber Testfälle, die ich auf verschiedenen Datensätzen ausführen möchte!


Keine Sorge, pytest hat eine coole Funktion, mit der Sie Ihr Gerät parametrisieren können. Schauen wir uns ein Beispiel an.

Angenommen, Ihr Produkt verfügt über eine CLI, die lokal verwaltet wird. Darüber hinaus verfügt Ihr Produkt über viele Standardparameter, die beim Start festgelegt werden, und Sie möchten alle Werte dieser Parameter überprüfen.

Sie könnten pytest für jeden dieser Parameter einen eigenen Testfall zu schreiben, aber mit pytest alles viel einfacher!

 @pytest.mark.parametrize(“setting_name, setting_value”, [('qdb_mem_usage', 'low'), ('report_crashes', 'yes'), ('stop_download_on_hang', 'no'), ('stop_download_on_disconnect', 'no'), ('reduce_connections_on_congestion', 'no'), ('global.max_web_users', '1024'), ('global.max_downloads', '5'), ('use_kernel_congestion_detection', 'no'), ('log_type', 'normal'), ('no_signature_check', 'no'), ('disable_xmlrpc', 'no'), ('disable_ntp', 'yes'), ('ssl_mode', 'tls_1_2'),])def test_settings_defaults(self, setting_name, setting_value): assert product_shell.run_command(setting_name) == \ self.”The current value for \'{0}\' is \'{1}\'.”.format(setting_name, setting_value), \ 'The {} default should be {}'.format(preference_name, preference_value) 

Cool, nicht wahr? Sie haben gerade 13 Testfälle geschrieben (jeder setzt einen anderen setting_value ). Wenn Sie Ihrem Produkt in Zukunft einen neuen Parameter hinzufügen, müssen Sie lediglich ein weiteres Tupel hinzufügen.

Wie lässt sich pytest in Benutzeroberflächentests mit Selen- und API-Tests integrieren?


Nun, Ihr Produkt verfügt möglicherweise über mehrere Schnittstellen. CLI - wie oben gesagt. Ähnlich wie die GUI und API. Bevor Sie Ihr Softwareprodukt bereitstellen, müssen Sie alle testen. In Unternehmenssoftware, in der mehrere Komponenten miteinander verbunden und voneinander abhängig sind, kann sich eine Änderung in einem Teil auf alle anderen auswirken.

Denken pytest daran, dass pytest nur ein Rahmen für einfache Tests ist, nicht für eine bestimmte Art von Tests. Das heißt, Sie können Tests für die GUI mit Selenium erstellen oder beispielsweise Tests für die API mit der requests von Python und sie mit pytest .

Auf hoher Ebene kann dies beispielsweise eine Überprüfung der Struktur des Repositorys sein.



Wie Sie in der obigen Abbildung sehen können, bietet sich eine gute Möglichkeit, die Komponenten zu trennen:

apiobjects : Ein guter Ort, um Wrapper zum Aufrufen von API-Endpunkten zu erstellen. Möglicherweise verfügen Sie über ein BaseAPIObject und eine abgeleitete Klasse, die Ihren Anforderungen entsprechen.

Helfer : Hier können Sie Ihre Hilfsmethoden hinzufügen.

lib : Bibliotheksdateien, die von verschiedenen Komponenten verwendet werden können, z. B. Ihre conftest in conftest , pageobjects usw.

pageobjects : Mit dem PageObjects- Architekturmuster können Klassen für verschiedene GUI-Seiten erstellt werden. Wir verwenden Webium , eine Bibliothek mit Implementierungen von Seitenobjektvorlagen für Python.

Suites : Sie können Ihre eigenen Sätze von Pylint-Checks für den Code erstellen. Diese helfen Ihnen dabei, mehr Vertrauen in die Qualität Ihres Codes zu gewinnen.

tests : Sie können Tests nach Ihren Wünschen katalogisieren. Dies erleichtert die Verwaltung und Überprüfung Ihrer Tests.

Ich habe es nur als Referenz mitgebracht, die Struktur des Repository und die Abhängigkeiten können nach Ihren persönlichen Bedürfnissen organisiert werden.

Ich habe viele Testfälle und möchte, dass sie parallel ausgeführt werden


Sie können viele Testfälle in Ihrem Set haben, und es kann vorkommen, dass Sie sie parallel ausführen müssen, um die gesamte Testausführungszeit zu verkürzen.

Pytest bietet ein fantastisches Plugin für parallele Testläufe namens pytest-xdist , das dem Basis-Pytest mehrere einzigartige Ausführungsmodi hinzufügt. Installiere dieses Plugin mit pip .

 pip install pytest-xdist 

Mal sehen, wie es mit einem Beispiel funktioniert.

Ich habe ein CloudApp-Repository für automatisierte Tests für meine Selenium-GUI-Tests. Darüber hinaus wird es ständig erweitert und mit neuen Tests aktualisiert. Mittlerweile gibt es Hunderte von Tests. Was ich tun möchte, ist sie parallel laufen zu lassen und die Gesamttestausführungszeit zu verringern.

pytest im Terminal einfach pytest in den Projektstammordner / pytest . Auf diese Weise können Sie alle Tests ausführen.

 pytest -s -v -n=2 



pytest-xdist führt alle Tests parallel durch!

Auf diese Weise können Sie auch mehrere Browser gleichzeitig ausführen.

Berichte


Pytest verfügt über eine integrierte Unterstützung für die Erstellung von Testergebnisdateien, die mit Jenkins, Bamboo oder anderen Servern für die kontinuierliche Integration geöffnet werden können. Verwenden Sie Folgendes:

 pytest test/file/path — junitxml=path 

Auf diese Weise können Sie eine hervorragende XML-Datei erstellen, die mit vielen Parsern geöffnet werden kann.

Fazit


Die Popularität von Pytest wächst von Jahr zu Jahr. Darüber hinaus bietet es eine leistungsstarke Community-Unterstützung, mit der Sie auf viele Erweiterungen wie pytest-django zugreifen können , mit deren Hilfe Sie Tests für Webanwendungen in Django schreiben können. Denken Sie daran, dass pytest unittest-Testfälle unterstützt. Wenn Sie also unittest verwenden, sollte pytest genauer betrachtet werden.

Quellen



Das ist alles. Wir sehen uns auf dem Platz !

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


All Articles