Vier gevallen verzamelen
Vervang de lege tabel door de vier gevraagde paren en gebruik count en expected als functieparameters.
Je hebt vier bijna gelijke testfuncties geschreven: alleen de invoer en de verwachte uitkomst verschillen. Als je dezelfde vergelijking blijft kopiëren, moet je een verbetering op meerdere plaatsen doorvoeren. Een tabel met testgegevens maakt die herhaling overzichtelijker.
Parametrisatie laat pytest één testfunctie meerdere keren uitvoeren met verschillende gegevens. De decorator @pytest.mark.parametrize staat direct boven de functie. Het eerste argument noemt de parameters; het tweede bevat de rijen met hun waarden.
Bij "text,expected" krijgt iedere rij twee waarden. De eerste gaat naar text en de tweede naar expected. Gebruik diezelfde namen in de functiedefinitie, zodat pytest weet waar de waarden horen.
Het eerste voorbeeld controleert een eenvoudige formatter. Iedere rij heeft een eigen, vooraf berekende verwachting. De rapporteur laat zien dat één functie drie afzonderlijke pytest-gevallen oplevert.
import pytest
@pytest.mark.parametrize("text,expected", [(" Sam ", "Sam"), ("", ""), (" Mila", "Mila")])
def test_name(text, expected):
assert text.strip() == expectedimport contextlib, io, pytest
class Recorded:
def __init__(self):
self.count = 0
self.outcomes = []
def pytest_collection_modifyitems(self, items):
self.count = len(items)
def pytest_runtest_logreport(self, report):
if report.when == "call":
self.outcomes.append(report.outcome)
recorded = Recorded()
with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
status = pytest.main(["-q", "--capture=sys", "-p", "no:cacheprovider", "test_format.py"], plugins=[recorded])
print("gevonden:", recorded.count)
print("geslaagd:", recorded.outcomes.count("passed"))
print("mislukt:", recorded.outcomes.count("failed"))
print("status:", int(status))gevonden: 3 geslaagd: 3 mislukt: 0 status: 0
Een testgeval bestaat hier uit invoer plus verwachting. Kies beide vanuit de afspraak die je wilt controleren. Als je de verwachting met dezelfde functie berekent als de ontvangen waarde, kan dezelfde fout aan beide kanten ontstaan.
Schrijf daarom niet (4, rates.shipping(4)) in de tabel. Reken de uitkomst zelf na: vier eenheden van negen kosten zesendertig. De functie wordt pas binnen de test aangeroepen voor de echte uitkomst.
Een goed gekozen rij onderzoekt iets anders dan de vorige. Een lege hoeveelheid, precies één eenheid en meerdere eenheden kunnen verschillende fouten zichtbaar maken. Vier keer dezelfde invoer opschrijven levert vier uitvoeringen, maar weinig extra zekerheid.
Met een gewone lus in één test stopt de uitvoering bij de eerste mislukte assertie. Met parametrisatie verzamelt pytest afzonderlijke gevallen voordat het ze uitvoert. Een fout in één rij verhindert daardoor niet dat de andere rijen hun eigen resultaat krijgen.
Het tweede voorbeeld heeft bewust één verkeerde verwachting. Je ziet twee gevallen, waarvan er één slaagt en één mislukt. De fout zit hier in de testgegevens: controleer de afgesproken bewerking voordat je de productcode verandert.
import pytest
@pytest.mark.parametrize("text,expected", [(" sam ", "sam"), ("MILA", "Mila")])
def test_name(text, expected):
assert text.strip() == expectedimport contextlib, io, pytest
class Recorded:
def __init__(self):
self.count = 0
self.outcomes = []
def pytest_collection_modifyitems(self, items):
self.count = len(items)
def pytest_runtest_logreport(self, report):
if report.when == "call":
self.outcomes.append(report.outcome)
recorded = Recorded()
with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
status = pytest.main(["-q", "--capture=sys", "-p", "no:cacheprovider", "test_format.py"], plugins=[recorded])
print("gevonden:", recorded.count)
print("geslaagd:", recorded.outcomes.count("passed"))
print("mislukt:", recorded.outcomes.count("failed"))
print("status:", int(status))gevonden: 2 geslaagd: 1 mislukt: 1 status: 1
De namen in de decorator moeten overeenkomen met de functieparameters. Een rij met maar één waarde past niet bij twee genoemde namen. Pytest kan de test dan niet correct verzamelen; dat is een andere situatie dan een uitgevoerde vergelijking die onwaar is.
Een lege tabel is evenmin een nuttige controle. Bij de standaardinstellingen wordt het lege parametergeval overgeslagen. Kijk dus naar de werkelijk verzamelde gegevens en uitgevoerde controles, niet alleen naar de groene kleur van een eindstatus.
De vaste module rates berekent negen per eenheid voor een niet-negatief geheel aantal. Maak één geparametriseerde functie test_shipping(count, expected) met de rijen (0, 0), (1, 9), (4, 36) en (7, 63). Vergelijk in die functie de echte uitkomst met expected.
De les controleert echte afzonderlijke pytest-gevallen en laat je test ook tegen gerichte rekenfouten lopen. Alleen vier waarden opsommen is dus onvoldoende: de test moet hun uitkomsten daadwerkelijk controleren.
Vervang de lege tabel door de vier gevraagde paren en gebruik count en expected als functieparameters.
Laat je assertie bewijzen dat nul eenheden nul kost; een fout die minimaal één eenheid rekent moet worden gevonden.
Vergelijk rates.shipping(count) met expected, zodat een functie die altijd negen teruggeeft niet door de test komt.
Neem ook zeven eenheden met verwachting 63 op; je test moet een onterechte bovengrens van vijf ontdekken.
Hierna maak je gedeelde testvoorbereiding zonder veranderlijke toestand tussen tests te laten lekken.
Voer je code uit en ontdek
wat je hebt gemaakt.
Je hoeft het niet in één keer goed te doen. Na het uitvoeren zie je hier welke stappen al kloppen.