Pytestarmaturer

Fuldført

Armaturer er pytesthjælpefunktioner, der bruges til at oprette modulære, skalerbare og vedligeholdbare test. Du kan bruge armaturer til at konfigurere forudsætninger for test, f.eks. databaseforbindelser, oprettelse af testdata eller konfiguration af en systemtilstand, der kræves, før en test kan køre. De kan også bruges til oprydning, når testene er færdige med at køre.

Nøgleegenskaberne for pytestarmaturer omfatter:

  • områdekontrolelement: Armaturer kan konfigureres til at have forskellige områder ved hjælp af parameteren scope (f.eks. function, class, moduleeller session), som bestemmer, hvor ofte armaturet kaldes.
  • Håndtering af opsætning og nedrivning: Pytest administrerer livscyklussen for inventar, automatisk konfiguration og nedrivning efter behov.
  • Afhængighedsinjektion: Armaturer indsprøjtes i testfunktioner som argumenter, hvilket gør det klart, hvilke test der er afhængige af hvilke inventar.
  • Genbrugelighed og modularitet: Armaturer kan defineres på ét sted og bruges på tværs af flere testfunktioner, moduler eller endda projekter.

Oprettelse af et midlertidigt filarmatur

Når du skriver test, der interagerer med filer, er det almindeligt at have brug for midlertidige filer, der ikke roder filsystemet efter test. Med pytest kan vi oprette et fast inventar, der konfigurerer en midlertidig fil. Armaturet bruger Pythons tempfile modul til at generere midlertidige filer sikkert og sikre, at de kan bruges og slettes, uden at det påvirker det lokale miljø. (I denne indledende version af vores armatur slettes filen ikke automatisk på grund af flaget delete=False. Vi behandler sletning af filer senere.)

Sådan ser armaturet ud:

import pytest
import tempfile

@pytest.fixture
def tmp_file():
    def create():
        # Create a named temporary file that persists beyond the function scope
        temp = tempfile.NamedTemporaryFile(delete=False)
        return temp.name
    return create

I denne konfiguration fungerer tmp_file() som armaturet. Armaturets navn er, hvordan testene refererer til det. I armaturet opretter den indlejrede funktion create() kun filen, når den kaldes, i stedet for ved opsætning af armaturet. Dette giver mulighed for præcis kontrol over, hvornår den midlertidige fil oprettes, hvilket er nyttigt i test, hvor timing og filtilstand er kritisk.

I den indlejrede funktion create()oprettes der en midlertidig fil, og derefter returneres den absolutte sti til den. Her er et eksempel på, hvordan en test kan bruge den armatur, vi skrev:

import os

def test_file(tmp_file):
    path = tmp_file()
    assert os.path.exists(path)

En test bruger en armatur ved at angive navnet på armaturet som et argument. Vores simple use case kan nemt udvides ved at skrive til filen eller foretage ændringer, f.eks. ændre tilladelser eller ejerskab.

Områdestyring

I pytest er administration af testressourcernes livscyklus gennem opsætnings- og nedrivningsrutiner afgørende for at vedligeholde rene og effektive testmiljøer. Du vil også beskytte integriteten af test ved at sikre, at hver test starter med en kendt, ensartet tilstand. Pytestarmaturer fungerer som standard med et function omfang, som påvirker funktionsmåden på to måder:

  • livscyklus pr. test: Armaturets returværdi genberegnes for hver testfunktion, der bruger den, og sikrer, at hver test fungerer med en ny tilstand.
  • Oprydning efter hver brug: Alle nødvendige oprydningshandlinger udføres efter hver test, der anvender armaturet.

Pytest gør det også muligt at bruge fast inventar mere bredt for at optimere ydeevnen og ressourceforbruget. Scoping er især nyttig i situationer som administration af databasetilstand, eller når du har komplekse tilstandskonfigurationer, der er tidskrævende at etablere. De fire tilgængelige områder er:

  • function: Standardomfanget udføres armaturet én gang pr. test
  • class: Armaturet kører én gang pr. testklasse.
  • module: Kører én gang for et modul.
  • session: Kører én gang pr. testsession. Dette område er nyttigt til dyre handlinger, der skal bevares i hele testsessionen, f.eks. initialisering af en tjeneste eller start af en databaseserver.

I dette tilfælde betyder , der kører én gang, at returværdien cachelagres. Så en armatur, der har et omfang af "modul", kan blive kaldt flere gange i et testmodul, men returværdien er den for den første test, der kaldte den.

Sådan ser tmp_file() armatur ud med et modulomfang:

import pytest
import tempfile

@pytest.fixture(scope="module")
def tmp_file():
    def create():
        temp = tempfile.NamedTemporaryFile(delete=False)
        return temp.name
    return create

Oprydningsstyring

Den tidligere kode, der angiver tmp_file fastgørelse, opretter en midlertidig fil, men den håndterer ikke automatisk oprydning, når testene er fuldført. Hvis du vil sikre dig, at midlertidige filer ikke efterlades, kan du bruge pytests request armatur til at registrere en oprydningsfunktion.

Sådan kan du ændre tmp_file armatur, så det omfatter automatisk oprydning:

import pytest
import tempfile
import os

@pytest.fixture(scope="module")
def tmp_file(request):
    # Create a temporary file that persists beyond the function scope
    temp = tempfile.NamedTemporaryFile(delete=False)

    def create():
        # Returns the path of the temporary file
        return temp.name

    def cleanup():
        # Remove the file after the tests are done
        os.remove(temp.name)

    # Register the cleanup function to be called after the last test in the module
    request.addfinalizer(cleanup)

    return create

Når du bruger request.addfinalizer() og overfører funktionen indlejrede cleanup(), kaldes oprydningen afhængigt af omfanget. I dette tilfælde er området module, så efter alle test i et modul kalder pytest denne oprydningsfunktion.

Brug af conftest.py

I stedet for at inkludere dine armaturer i dine testfiler kan du gemme dem i en conftest.py fil. Alle armaturer i conftest.py er automatisk tilgængelige for dine test i den samme mappe uden at skulle importere dem eksplicit.

Udforskning af indbyggede installationer

Pytest har mange indbyggede armaturer, der er designet til at strømline test. Disse armaturer kan håndtere konfiguration og oprydning automatisk, så du kan fokusere på at skrive dine testcases i stedet for teststyring.

Vigtige indbyggede installationer omfatter:

  • cache: Bruges til at oprette og administrere cache på testniveau, hvilket er nyttigt til lagring af data mellem testsessioner.
  • capsys: Registrerer og tillader inspektion af stderr og stdout, hvilket gør det nemt at inspicere og teste konsoloutput.
  • tmpdir: Indeholder en midlertidig mappe til filer, der skal oprettes og bruges under test.
  • monkeypatch: Gør det muligt at ændre funktionsmåden og værdierne for objekter, funktioner og dit os-miljø på en sikker måde.

Rollen som abepatch i test

Det kan være en udfordring at teste kode, der er tæt integreret med eksterne ressourcer, f.eks. databaser eller eksterne API'er, på grund af de involverede afhængigheder. En teknik, der kaldes abe patching involverer midlertidigt at ændre dit system under testkørsler, hvilket giver mulighed for uafhængighed fra eksterne systemer og giver dig mulighed for sikkert at ændre tilstanden og funktionsmåden for dit operativsystem miljø under test.

Her er et eksempel på, hvordan du tilsidesætter funktionen os.path.exists() ved hjælp af monkeypatch-armaturet:

import os

def test_os(monkeypatch):
    # Override os.path.exists to always return False
    monkeypatch.setattr('os.path.exists', lambda x: False)
    assert not os.path.exists('/')

Du kan også bruge metoden setattr() med direkte reference til objektet og attributten:

def test_os(monkeypatch):
    # Specify the object and attribute to override
    monkeypatch.setattr(os.path, 'exists', lambda x: False)
    assert not os.path.exists('/')

Ud over at angive attributter og tilsidesætte metoder kan monkeypatch-armaturet angive og slette miljøvariabler, ændre ordbogsværdier og ændre systemstier. Den monkeypatch armaturet automatisk vender tilbage eventuelle ændringer efter hver test, men der bør stadig tages forsigtighed, når du bruger monkeypatch armatur. Her er nogle grunde til at være forsigtig, når du bruger den:

- kodeklarhed og vedligeholdelse: Hvis du bruger monkeypatch eller bruger den på komplekse måder, kan det gøre det sværere at forstå og vedligeholde testen. Når du læser dine testresultater, er det muligvis ikke umiddelbart klart, hvordan komponenterne skal fungere normalt i forhold til, hvordan de ændres til test. - Test validitet: Monkeypatching kan nogle gange føre til test, der passerer under kunstige forhold, der er meget forskellige fra produktionsmiljøet. Dette kan skabe en falsk følelse af sikkerhed, da testene kan bestå, fordi testen ændrede systemets funktionsmåde for dramatisk. - Overdependence for implementeringsoplysninger: Test, der er afhængige af abepatching, kan være tæt forbundet med specifikke implementeringsoplysninger for den kode, de tester. Dette kan gøre testene skrøbelige og modtagelige for brud med selv mindre ændringer af den underliggende kodebase. - fejlfinding af kompleksitet: Fejlfindingstest, der bruger monkeypatch, kan være mere komplekse, især hvis programrettelsen ændrer grundlæggende aspekter af programfunktionsmåden. Hvis du forstår, hvorfor en test mislykkes, kan det kræve et dybere indblik i, hvordan komponenterne ændres under testen.

Selvom monkeypatch er et effektivt værktøj til oprettelse af isolerede og kontrollerede testmiljøer, bør det bruges fornuftigt og med en klar forståelse af, hvordan det påvirker testpakken og programmets funktionsmåde.