A Pytest alapjai
Kezdjük el a tesztelést a Pytesttel. Ahogy az előző leckében említettük, a Pytest nagy mértékben konfigurálható, és képes kezelni az összetett tesztcsomagokat, de nem igényel sokat a tesztek írásához. Valójában minél egyszerűbb egy keretrendszer, annál jobb teszteket írhat.
A szakasz végére mindent meg kell adnia, ami az első tesztek írásához és a Pytesttel való futtatásához szükséges.
Szabályok
Mielőtt belemerülnénk a tesztek írásába, ki kell fednünk néhány olyan tesztelési konvenciót, amelyekre a Pytest támaszkodik.
A Pythonban nincs sok szigorú szabály a tesztfájlokra, a tesztkönyvtárakra vagy az általános tesztelési elrendezésekre. Ezen szabályok ismeretében kihasználhatja az automatikus tesztfelderítést és -végrehajtást anélkül, hogy további konfigurációra volna szükség.
Könyvtár és tesztfájlok tesztelése
A tesztek fő könyvtára a tesztkönyvtár . Ezt a könyvtárat a projekt gyökérszintjén helyezheti el, de a kódmodulok mellett nem szokatlan.
Feljegyzés
Ebben a modulban alapértelmezés szerint egy projekt gyökerénél használunk teszteket .
Nézzük meg, hogyan néz ki egy kis Python-projekt gyökere:jformat
.
├── README.md
├── jformat
│ ├── __init__.py
│ └── main.py
├── setup.py
└── tests
└── test_main.py
A tesztkönyvtár a projekt gyökérkönyvtárában található egyetlen tesztfájllal. Ebben az esetben a tesztfájl neve test_main.py. Ez a példa két kritikus konvenciót mutat be:
- Tesztfájlok és beágyazott tesztkönyvtárak elhelyezéséhez használjon tesztkönyvtárat.
- Tesztfájlokat tesztelő előtag. Az előtag azt jelzi, hogy a fájl tesztkódot tartalmaz.
Figyelemfelhívás
Ne használjon test (egyedi űrlapot) könyvtárnévként. A test név egy Python-modul, így az azonos nevű könyvtár létrehozása felülírná azt. Mindig használja a többes számot tests .
Függvények tesztelése
A Pytest használatának egyik erős argumentuma, hogy lehetővé teszi a tesztfüggvények írását. A tesztelési fájlokhoz hasonlóan a tesztfüggvényeket előtaggal test_kell megadni. Az test_ előtag biztosítja, hogy a Pytest összegyűjtse és végrehajtsa a tesztet.
Így néz ki egy egyszerű tesztfüggvény:
def test_main():
assert "a string value" == "a string value"
Feljegyzés
Ha ismeri unittest, meglepődhet, amikor a tesztfüggvényben látja assert alkalmazását. Később részletesebben ismertetjük az egyszerű állításokat, de a Pytest segítségével egyszerű állításokkal gazdag hibajelentést kaphat.
Tesztosztályok és tesztelési módszerek
A fájlok és függvények konvencióihoz hasonlóan a tesztosztályok és a tesztelési módszerek a következő konvenciók használatát használják:
- A tesztosztályok előtagja
Test - A tesztelési módszerek előtagja a következő:
test_
A Python kódtárának alapvető különbsége unittest , hogy nincs szükség öröklésre.
Az alábbi példa ezeket az előtagokat és más Python-elnevezési konvenciókat használja osztályokhoz és metódusokhoz. Egy kis tesztelési osztályt mutat be, amely egy alkalmazásban ellenőrzi a felhasználóneveket.
class TestUser:
def test_username(self):
assert default() == "default username"
Tesztek futtatása
A Pytest egy teszt keretrendszer és egy tesztfuttató is. A tesztfuttató egy parancssorban futtatható végrehajtható fájl, amely alapvetően a következőkre képes:
- A tesztek gyűjtéséhez keresse meg az összes tesztfájlt, tesztosztályt és tesztfüggvényt egy tesztfuttatáshoz.
- Az összes teszt végrehajtásával kezdeményezheti a tesztfuttatást.
- Kövesse nyomon a hibákat, a hibákat és a tesztek átadását.
- Részletes jelentéskészítés a tesztfuttatás végén.
Feljegyzés
Mivel a Pytest egy külső kódtár, a használatához telepíteni kell .
Egy test_main.py fájl tartalma alapján láthatjuk, hogyan viselkedik a Pytest a tesztek futtatásával:
# contents of test_main.py file
def test_main():
assert True
A parancssorban, ugyanabban az elérési úton, ahol a test_main.py fájl létezik, futtathatjuk a pytest végrehajtható fájlt:
$ pytest
=========================== test session starts ============================
platform -- Python 3.10.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /private/tmp/project
collected 1 item
test_main.py . [100%]
============================ 1 passed in 0.00s =============================
A színfalak mögött a Pytest konfiguráció nélkül gyűjti össze a példatesztet a tesztfájlban.
A hatékony állítás
Eddig a teszt példáink mind egyszerű assert hívást használnak. A Pythonban az assert utasítást általában nem használják tesztekhez, mert az állítás sikertelensége esetén nincs megfelelő jelentéskészítés. A Pytest azonban nem rendelkezik ezzel a korlátozásokkal. A színfalak mögött a Pytest lehetővé teszi, hogy az utasítás gazdag összehasonlításokat végezzen anélkül, hogy a felhasználót több kód írására vagy bármi konfigurálására kényszeríti.
Az egyszerű assert utasítás használatával használhatja a Python operátorait, például , >, <!=, >=vagy <=. A Python összes operátora érvényes. Ez a képesség lehet a Pytest legfontosabb funkciója: nem kell új szintaxist tanulnia az állítások írásához.
Nézzük meg, hogy ez hogyan fordítható le a Python-objektumokkal való gyakori összehasonlítások során. Ebben az esetben vizsgáljuk meg a hibajelentést a hosszú sztringek összehasonlítása során:
================================= FAILURES =================================
____________________________ test_long_strings _____________________________
def test_long_strings():
left = "this is a very long strings to be compared with another long string"
right = "This is a very long string to be compared with another long string"
> assert left == right
E AssertionError: assert 'this is a ve...r long string' == 'This is a ve...r long string'
E - This is a very long string to be compared with another long string
E ? ^
E + this is a very long strings to be compared with another long string
E ? ^ +
test_main.py:4: AssertionError
A Pytest hasznos kontextust jelenít meg a hiba körül: helytelen burkolatot a sztring elején, és egy további karaktert egy szóban. A sztringeken túl azonban a Pytest más objektumokkal és adatstruktúrákkal is segíthet. Például a következőképpen viselkedik a listákkal:
________________________________ test_lists ________________________________
def test_lists():
left = ["sugar", "wheat", "coffee", "salt", "water", "milk"]
right = ["sugar", "coffee", "wheat", "salt", "water", "milk"]
> assert left == right
E AssertionError: assert ['sugar', 'wh...ater', 'milk'] == ['sugar', 'co...ater', 'milk']
E At index 1 diff: 'wheat' != 'coffee'
E Full diff:
E - ['sugar', 'coffee', 'wheat', 'salt', 'water', 'milk']
E ? ---------
E + ['sugar', 'wheat', 'coffee', 'salt', 'water', 'milk']
E ? +++++++++
test_main.py:9: AssertionError
Ez a jelentés azt azonosítja, hogy az 1. index (a lista második eleme) eltérő. Nem csak az indexszámot azonosítja, hanem a hiba ábrázolását is. Az elemek összehasonlításán kívül jelentéskészítést is végezhet, ha az elemek hiányoznak, és olyan információkat is megadhat, amelyek pontosan meg tudják állapítani, hogy melyik elem lehet. Az alábbi esetben ez a következő "milk":
________________________________ test_lists ________________________________
def test_lists():
left = ["sugar", "wheat", "coffee", "salt", "water", "milk"]
right = ["sugar", "wheat", "salt", "water", "milk"]
> assert left == right
E AssertionError: assert ['sugar', 'wh...ater', 'milk'] == ['sugar', 'wh...ater', 'milk']
E At index 2 diff: 'coffee' != 'salt'
E Left contains one more item: 'milk'
E Full diff:
E - ['sugar', 'wheat', 'salt', 'water', 'milk']
E + ['sugar', 'wheat', 'coffee', 'salt', 'water', 'milk']
E ? ++++++++++
test_main.py:9: AssertionError
Végül nézzük meg, hogyan viselkedik a szótárakkal. Két nagy szótár összehasonlítása túl sok lehet, ha vannak hibák, de a Pytest kiemelkedő feladatot végez a környezet biztosításában és a hiba rögzítésében:
____________________________ test_dictionaries _____________________________
def test_dictionaries():
left = {"street": "Ferry Ln.", "number": 39, "state": "Nevada", "zipcode": 30877, "county": "Frett"}
right = {"street": "Ferry Lane", "number": 38, "state": "Nevada", "zipcode": 30877, "county": "Frett"}
> assert left == right
E AssertionError: assert {'county': 'F...rry Ln.', ...} == {'county': 'F...ry Lane', ...}
E Omitting 3 identical items, use -vv to show
E Differing items:
E {'street': 'Ferry Ln.'} != {'street': 'Ferry Lane'}
E {'number': 39} != {'number': 38}
E Full diff:
E {
E 'county': 'Frett',...
E
E ...Full output truncated (12 lines hidden), use '-vv' to show
Ebben a tesztben két hiba van a szótárban. Az egyik az, hogy az "street" érték eltérő, a másik pedig az, hogy "number" nem egyezik.
A Pytest pontosan észleli ezeket a különbségeket (bár ez egyetlen tesztnek csak egy hibája). Mivel a szótárak sok elemet tartalmaznak, a Pytest kihagyja az azonos részeket, és csak a releváns tartalmat jeleníti meg. Nézzük meg, mi történik, ha a javasolt -vv jelölő használatával növeljük a kimenet részletességét:
____________________________ test_dictionaries _____________________________
def test_dictionaries():
left = {"street": "Ferry Ln.", "number": 39, "state": "Nevada", "zipcode": 30877, "county": "Frett"}
right = {"street": "Ferry Lane", "number": 38, "state": "Nevada", "zipcode": 30877, "county": "Frett"}
> assert left == right
E AssertionError: assert {'county': 'Frett',\n 'number': 39,\n 'state': 'Nevada',\n 'street': 'Ferry Ln.',\n 'zipcode': 30877} == {'county': 'Frett',\n 'number': 38,\n 'state': 'Nevada',\n 'street': 'Ferry Lane',\n 'zipcode': 30877}
E Common items:
E {'county': 'Frett', 'state': 'Nevada', 'zipcode': 30877}
E Differing items:
E {'number': 39} != {'number': 38}
E {'street': 'Ferry Ln.'} != {'street': 'Ferry Lane'}
E Full diff:
E {
E 'county': 'Frett',
E - 'number': 38,
E ? ^
E + 'number': 39,
E ? ^
E 'state': 'Nevada',
E - 'street': 'Ferry Lane',
E ? - ^
E + 'street': 'Ferry Ln.',
E ? ^
E 'zipcode': 30877,
E }
A futtatás pytest -vvrévén a jelentés növeli a részletek mennyiségét, és részletes összehasonlítást biztosít. Ez a jelentés nem csak a hibát észleli és jeleníti meg, hanem lehetővé teszi, hogy gyorsan elvégezzen módosításokat a probléma megoldásához.