Fixturi pytest și yield

  • 2 minute de citit
  • 6 exemple de cod

Disponibil și în English

Pe această pagină

Salut 👋

În acest articol scurt vreau să explic utilizarea cuvântului cheie yield în fixturile pytest.

Ce este pytest?

Pytest este un framework Python complex, folosit pentru scrierea testelor. Are multe funcționalități avansate și suportă plugin-uri. Multe proiecte preferă pytest în completarea bibliotecii unitttest din Python.

Ce este o fixture?

O fixture de test este o bucată de cod care fixează o funcționalitate comună necesară pentru scrierea testelor unitare. Această funcționalitate poate fi

  • o conexiune la baza de date
  • un server sau un client HTTP de test
  • crearea unui obiect complex

Puteți citi mai multe despre fixturile de test pe Wikipedia.

Ce face cuvântul cheie yield?

În Python, cuvântul cheie yield este folosit pentru scrierea funcțiilor generator. În pytest, yield poate fi folosit pentru a finaliza (curăța) după ce codul fixturii a fost executat. Documentația pytest afirmă următoarele.

„Fixturile „yield” folosesc yield în loc de return. Cu aceste fixturi, putem rula un cod și putem transmite un obiect înapoi fixturii/testului care le-a cerut, exact ca în cazul celorlalte fixturi.”

https://docs.pytest.org/en/6.2.x/fixture.html

Un exemplu de cod ar putea fi următorul:

@pytest.fixture()def my_object_fixture():    print("1. fixture code.")    yield MyObjectThatRequiresCleanUp()    print("4. fixture code after yield.")

Rularea unui test de probă care folosește fixture-ul va afișa:

collected 1 item                                                                                                                                                                       tests\test_my_object.py 1. fixture code.2. Initializing MyObjectThatRequiresCleanUp3. test code..4. fixture code after yield.

Rularea aceluiași test, dar acum cu fixture-ul my_object_fixture2, va afișa:

tests\test_my_object.py 1. fixture code.2. Initializing MyObjectThatRequiresCleanUp2.1 Entering3. test code..3.1 ExitingClean exit4. fixture code after yield.

Sper că am reușit să ilustrez, cu aceste exemple, ordinea în care se rulează codul de test și cel al fixturii.

Pentru a rula testele, am folosit pytest --capture=tee-sys . în rădăcina proiectului. Conținutul fișierelor este atașat la finalul acestui articol. Parametrul --capture este folosit pentru a captura și afișa stdout-ul testelor. Pytest afișează stdout doar pentru testele eșuate, iar deoarece testul nostru de probă trece întotdeauna, acest parametru a fost necesar.

Concluzie

Pytest este un framework de testare pentru Python care conține multe funcționalități și se scalează bine în proiectele mari.

Fixturile de test sunt o bucată de cod pentru „fixarea” mediului de testare, de exemplu o conexiune la baza de date sau un obiect care necesită un set specific de parametri la construire. În loc să duplicăm cod, fixarea creării obiectului într-o fixture face testele mai ușor de întreținut și de scris.

yield este un cuvânt cheie din Python și, când este folosit împreună cu fixturile pytest, îți oferă o modalitate elegantă, specifică Pythonului, de a curăța fixturile.

Mulțumesc pentru lectură! 📚


Conținutul fixturilor pytest plasate în tests/__init__.py

import pytestfrom my_object import MyObjectThatRequiresCleanUp@pytest.fixture()def my_object_fixture():    print("1. fixture code.")    yield MyObjectThatRequiresCleanUp()    print("4. fixture code after yield.")@pytest.fixture()def my_object_fixture2():    print("1. fixture code.")    with MyObjectThatRequiresCleanUp() as obj:        yield obj    print("4. fixture code after yield.")

Conținutul fișierului my_object.py

class MyObjectThatRequiresCleanUp:    def __init__(self):        print("2. Initializing MyObjectThatRequiresCleanUp")    def __enter__(self):        print("2.1 Entering")        return self    def __exit__(self, exc_type, exc_val, exc_tb):        print("3.1 Exiting")        if exc_type is None:            print("Clean exit")        else:            print("Exception occurred: {}".format(exc_type))

Conținutul fișierului test_my_object.py plasat în tests/test_my_object.py

from tests import my_object_fixturedef test_my_object(my_object_fixture):    print("3. test code.")