PyTest-veiledning: Hva er, hvordan installeres, rammeverk, påstander
Hva er PyTest?
PyTest er et testrammeverk som lar brukere skrive testkoder ved hjelp av Python programmeringsspråk. Det hjelper deg å skrive enkle og skalerbare testtilfeller for databaser, APIer eller brukergrensesnitt. PyTest brukes hovedsakelig til å skrive tester for APIer. Det hjelper å skrive tester fra enkle enhetstester til komplekse funksjonstester.
Hvorfor bruke PyTest?
Noen av fordelene med pytest er
- Veldig lett å starte med på grunn av sin enkle og enkle syntaks.
- Kan kjøre tester parallelt.
- Kan kjøre en spesifikk test eller et undersett av tester
- Oppdag tester automatisk
- Hopp over tester
- Åpen kilde
Hvordan installere PyTest
Følgende er en prosess for hvordan du installerer PyTest:
Trinn 1) Du kan installere pytest ved å
pip install pytest==2.9.1
Når installasjonen er fullført kan du bekrefte den med av
py.test -h
Dette vil vise hjelpen
Første grunnleggende PyTest
Nå skal vi lære hvordan du bruker Pytest med et grunnleggende PyTest-eksempel.
Opprett en mappe study_pytest. Vi skal lage testfilene våre i denne mappen.
Naviger til den mappen på kommandolinjen.
Opprett en fil med navnet test_sample1.py inne i mappen
Legg til koden nedenfor i den og lagre
import pytest def test_file1_method1(): x=5 y=6 assert x+1 == y,"test failed" assert x == y,"test failed" def test_file1_method2(): x=5 y=6 assert x+1 == y,"test failed"
Kjør testen ved å bruke kommandoen
py.test
Du får utdata som
test_sample1.py F. ============================================== FAILURES ======================================== ____________________________________________ test_sample1 ______________________________________ def test_file1_method1(): x=5 y=6 assert x+1 == y,"test failed" > assert x == y,"test failed" E AssertionError: test failed E assert 5 == 6 test_sample1.py:6: AssertionError
Her i test_sample1.py F.
F sier fiasko
Prikk(.) sier suksess.
I feildelen kan du se de(n) mislykkede metoden(e) og feillinjen. Her betyr x==y 5==6 som er usant.
Neste i denne PyTest-opplæringen vil vi lære om påstand i PyTest.
Påstander i PyTest
Pytest-påstander er sjekker som returnerer enten True eller False status. I Python Pytest, hvis en påstand mislykkes i en testmetode, stoppes kjøringen av denne metoden der. Den gjenværende koden i den testmetoden blir ikke utført, og Pytest-påstander vil fortsette med neste testmetode.
Pytest Assert eksempler:
assert "hello" == "Hai" is an assertion failure. assert 4==4 is a successful assertion assert True is a successful assertion assert False is an assertion failure.
Vurder
assert x == y,"test failed because x=" + str(x) + " y=" + str(y)
Plasser denne koden i test_file1_method1() i stedet for påstanden
assert x == y,"test failed"
Å kjøre testen vil gi feilen som AssertionError: test mislyktes x=5 y=6
Hvordan PyTest identifiserer testfilene og testmetodene
Som standard identifiserer pytest bare filnavnene som begynner med test_ eller slutter med _test som testfilene. Vi kan imidlertid eksplisitt nevne andre filnavn (forklart senere). Pytest krever testmetodenavnene til å begynne med "test." Alle andre metodenavn vil bli ignorert selv om vi eksplisitt ber om å kjøre disse metodene.
Se noen eksempler på gyldige og ugyldige pytest-filnavn
test_login.py - valid login_test.py - valid testlogin.py -invalid logintest.py -invalid
Merk: Ja, vi kan eksplisitt be pytest om å velge testlogin.py og logintest.py
Se noen eksempler på gyldige og ugyldige pytest-testmetoder
def test_file1_method1(): - valid def testfile1_method1(): - valid def file1_method1(): - invalid
Merk: Selv om vi eksplisitt nevner file1_method1() vil ikke pytest kjøre denne metoden.
Kjør flere tester fra en bestemt fil og flere filer
For øyeblikket, inne i mappen study_pytest, har vi en fil test_sample1.py. Anta at vi har flere filer, si test_sample2.py, test_sample3.py. For å kjøre alle testene fra alle filene i mappen og undermappene trenger vi bare å kjøre pytest-kommandoen.
py.test
Dette vil kjøre alle filnavnene som starter med test_ og filnavnene som slutter med _test i den mappen og undermapper under den mappen.
For å kjøre tester kun fra en bestemt fil, kan vi bruke py.test
py.test test_sample1.py
Kjør et undersett av hele testen med PyTest
Noen ganger ønsker vi ikke å kjøre hele testpakken. Pytest lar oss kjøre spesifikke tester. Vi kan gjøre det på 2 måter
- Gruppering av testnavn etter understrengmatching
- Gruppering av tester etter markører
Vi har allerede test_sample1.py. Opprett en fil test_sample2.py og legg til koden nedenfor i den
def test_file2_method1(): x=5 y=6 assert x+1 == y,"test failed" assert x == y,"test failed because x=" + str(x) + " y=" + str(y) def test_file2_method2(): x=5 y=6 assert x+1 == y,"test failed"
Så vi har for tiden
• test_sample1.py • test_file1_method1() • test_file1_method2() • test_sample2.py • test_file2_method1() • test_file2_method2()
Alternativ 1) Kjør tester ved å matche understrenger
Her for å kjøre alle testene med metode1 i navnet må vi kjøre
py.test -k method1 -v -k <expression> is used to represent the substring to match -v increases the verbosity
Så å kjøre py.test -k method1 -v vil gi deg følgende resultat
test_sample2.py::test_file2_method1 FAILED test_sample1.py::test_file1_method1 FAILED ============================================== FAILURES ============================================== _________________________________________ test_file2_method1 _________________________________________ def test_file2_method1(): x=5 y=6 assert x+1 == y,"test failed" > assert x == y,"test failed because x=" + str(x) + " y=" + str(y) E AssertionError: test failed because x=5 y=6 E assert 5 == 6 test_sample2.py:5: AssertionError _________________________________________ test_file1_method1 _________________________________________ @pytest.mark.only def test_file1_method1(): x=5 y=6 assert x+1 == y,"test failed" > assert x == y,"test failed because x=" + str(x) + " y=" + str(y) E AssertionError: test failed because x=5 y=6 E assert 5 == 6 test_sample1.py:8: AssertionError ================================= 2 tests deselected by '-kmethod1' ================================== =============================== 2 failed, 2 deselected in 0.02 seconds ===============================
Her kan du se mot slutten 2 tester fravalgt av '-kmethod1' som er test_fil1_metode2 og testfil2_metode2
Prøv å løpe med forskjellige kombinasjoner som:
py.test -k method -v - will run all the four methods py.test -k methods -v – will not run any test as there is no test name matches the substring 'methods'
Alternativ 2) Kjør tester med markører
Pytest lar oss angi ulike attributter for testmetodene ved å bruke pytest-markører, @pytest.mark . For å bruke markører i testfilen, må vi importere pytest på testfilene.
Her vil vi bruke forskjellige markørnavn på testmetoder og kjøre spesifikke tester basert på markørnavn. Vi kan definere markørene på hvert testnavn ved å bruke
@pytest.mark.<name>.
Vi definerer markører sett1 og sett2 på testmetodene, og vi vil kjøre testen ved å bruke markørnavnene. Oppdater testfilene med følgende kode
test_sample1.py
import pytest @pytest.mark.set1 def test_file1_method1(): x=5 y=6 assert x+1 == y,"test failed" assert x == y,"test failed because x=" + str(x) + " y=" + str(y) @pytest.mark.set2 def test_file1_method2(): x=5 y=6 assert x+1 == y,"test failed"
test_sample2.py
import pytest @pytest.mark.set1 def test_file2_method1(): x=5 y=6 assert x+1 == y,"test failed" assert x == y,"test failed because x=" + str(x) + " y=" + str(y) @pytest.mark.set1 def test_file2_method2(): x=5 y=6 assert x+1 == y,"test failed"
Vi kan kjøre den merkede testen ved
py.test -m <name> -m <name> mentions the marker name
Kjør py.test -m set1. Dette vil kjøre metodene test_file1_method1, test_file2_method1, test_file2_method2.
Å kjøre py.test -m set2 vil kjøre test_fil1_metode2.
Kjør tester parallelt med Pytest
Vanligvis vil en testpakke ha flere testfiler og hundrevis av testmetoder som vil ta lang tid å utføre. Pytest lar oss kjøre tester parallelt.
For det må vi først installere pytest-xdist ved å kjøre
pip install pytest-xdist
Du kan kjøre tester nå ved å
py.test -n 4
-n kjører testene ved å bruke flere arbeidere. I kommandoen ovenfor vil det være 4 arbeidere til å kjøre testen.
Pytest-armaturer
Fixtures brukes når vi ønsker å kjøre litt kode før hver testmetode. Så i stedet for å gjenta den samme koden i hver test, definerer vi inventar. Vanligvis brukes inventar for å initialisere databasetilkoblinger, sende basen osv
En metode merkes som en Pytest-fixtur ved å merke med
@pytest.fixture
En testmetode kan bruke en Pytest-fixtur ved å nevne fixturen som en inngangsparameter.
Opprett en ny fil test_basic_fixture.py med følgende kode
import pytest @pytest.fixture def supply_AA_BB_CC(): aa=25 bb =35 cc=45 return [aa,bb,cc] def test_comparewithAA(supply_AA_BB_CC): zz=35 assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed" def test_comparewithBB(supply_AA_BB_CC): zz=35 assert supply_AA_BB_CC[1]==zz,"bb and zz comparison failed" def test_comparewithCC(supply_AA_BB_CC): zz=35 assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"
Her
- Vi har en armatur som heter supply_AA_BB_CC. Denne metoden vil returnere en liste med 3 verdier.
- Vi har 3 testmetoder som sammenligner med hver av verdiene.
Hver av testfunksjonene har et input-argument hvis navn samsvarer med en tilgjengelig fixtur. Pytest påkaller deretter den tilsvarende fixturmetoden og de returnerte verdiene vil bli lagret i input-argumentet , her listen [25,35,45]. Nå brukes listeelementene i testmetoder for sammenligningen.
Kjør nå testen og se resultatet
py.test test_basic_fixture
test_basic_fixture.py::test_comparewithAA FAILED test_basic_fixture.py::test_comparewithBB PASSED test_basic_fixture.py::test_comparewithCC FAILED ============================================== FAILURES ============================================== _________________________________________ test_comparewithAA _________________________________________ supply_AA_BB_CC = [25, 35, 45] def test_comparewithAA(supply_AA_BB_CC): zz=35 > assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed" E AssertionError: aa and zz comparison failed E assert 25 == 35 test_basic_fixture.py:10: AssertionError _________________________________________ test_comparewithCC _________________________________________ supply_AA_BB_CC = [25, 35, 45] def test_comparewithCC(supply_AA_BB_CC): zz=35 > assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed" E AssertionError: cc and zz comparison failed E assert 45 == 35 test_basic_fixture.py:16: AssertionError ================================= 2 failed, 1 passed in 0.05 seconds =================================
Testen test_comparewithBB er bestått siden zz=BB=35, og de resterende 2 testene mislykkes.
Festemetoden har et omfang bare innenfor den testfilen den er definert. Hvis vi prøver å få tilgang til fiksturen i en annen testfil, får vi en feilmelding som sier fixture 'supply_AA_BB_CC' ikke funnet for testmetodene i andre filer.
For å bruke samme fixtur mot flere testfiler, vil vi lage fixturmetoder i en fil kalt conftest.py.
La oss se dette ved PyTest-eksemplet nedenfor. Opprett 3 filer conftest.py, test_basic_fixture.py, test_basic_fixture2.py med følgende kode
conftest.py
import pytest @pytest.fixture def supply_AA_BB_CC(): aa=25 bb =35 cc=45 return [aa,bb,cc]
test_basic_fixture.py
import pytest def test_comparewithAA(supply_AA_BB_CC): zz=35 assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed" def test_comparewithBB(supply_AA_BB_CC): zz=35 assert supply_AA_BB_CC[1]==zz,"bb and zz comparison failed" def test_comparewithCC(supply_AA_BB_CC): zz=35 assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"
test_basic_fixture2.py
import pytest def test_comparewithAA_file2(supply_AA_BB_CC): zz=25 assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed" def test_comparewithBB_file2(supply_AA_BB_CC): zz=25 assert supply_AA_BB_CC[1]==zz,"bb and zz comparison failed" def test_comparewithCC_file2(supply_AA_BB_CC): zz=25 assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"
pytest vil lete etter fixturen i testfilen først, og hvis den ikke finnes vil den lete i conftest.py
Kjør testen med py.test -k test_comparewith -v for å få resultatet som nedenfor
test_basic_fixture.py::test_comparewithAA FAILED test_basic_fixture.py::test_comparewithBB PASSED test_basic_fixture.py::test_comparewithCC FAILED test_basic_fixture2.py::test_comparewithAA_file2 PASSED test_basic_fixture2.py::test_comparewithBB_file2 FAILED test_basic_fixture2.py::test_comparewithCC_file2 FAILED
Pytest-parameterisert test
Hensikten med å parameterisere en test er å kjøre en test mot flere sett med argumenter. Vi kan gjøre dette ved å @pytest.mark.parametrize.
Vi vil se dette med PyTest-eksemplet nedenfor. Her skal vi sende 3 argumenter til en testmetode. Denne testmetoden vil legge til de to første argumentene og sammenligne dem med det tredje argumentet.
Opprett testfilen test_addition.py med koden nedenfor
import pytest @pytest.mark.parametrize("input1, input2, output",[(5,5,10),(3,5,12)]) def test_add(input1, input2, output): assert input1+input2 == output,"failed"
Her aksepterer testmetoden 3 argumenter - input1, input2, output. Den legger til input1 og input2 og sammenligner med utgangen.
La oss kjøre testen med py.test -k test_add -v og se resultatet
test_addition.py::test_add[5-5-10] PASSED test_addition.py::test_add[3-5-12] FAILED ============================================== FAILURES ============================================== __________________________________________ test_add[3-5-12] __________________________________________ input1 = 3, input2 = 5, output = 12 @pytest.mark.parametrize("input1, input2, output",[(5,5,10),(3,5,12)]) def test_add(input1, input2, output): > assert input1+input2 == output,"failed" E AssertionError: failed E assert (3 + 5) == 12 test_addition.py:5: AssertionError
Du kan se testene kjørt 2 ganger – en sjekker 5+5 ==10 og den andre sjekker 3+5 ==12
test_addition.py::test_add[5-5-10] BEVATT
test_addition.py::test_add[3-5-12] MISLYKKES
Pytest Xfail / Hopp over tester
Det vil være noen situasjoner der vi ikke ønsker å utføre en test, eller en testforsøk er ikke relevant for et bestemt tidspunkt. I disse situasjonene har vi muligheten til å Xfail testen eller hoppe over testene
Den xmislykkede testen vil bli utført, men den vil ikke bli regnet som delvis mislykkede eller beståtte tester. Det vil ikke vises noen sporing hvis testen mislykkes. Vi kan mislykkes tester ved hjelp av
@pytest.mark.xfail.
Å hoppe over en test betyr at testen ikke vil bli utført. Vi kan hoppe over tester ved hjelp av
@pytest.mark.hopp.
Rediger test_addition.py med koden nedenfor
import pytest @pytest.mark.skip def test_add_1(): assert 100+200 == 400,"failed" @pytest.mark.skip def test_add_2(): assert 100+200 == 300,"failed" @pytest.mark.xfail def test_add_3(): assert 15+13 == 28,"failed" @pytest.mark.xfail def test_add_4(): assert 15+13 == 100,"failed" def test_add_5(): assert 3+2 == 5,"failed" def test_add_6(): assert 3+2 == 6,"failed"
Her
- test_add_1 og test_add_2 hoppes over og vil ikke bli utført.
- test_add_3 og test_add_4 mislyktes. Disse testene vil bli utført og vil være en del av xmislykkede (ved testfeil) eller xbestått (ved testbestått) tester. Det vil ikke være noen sporing for feil.
- test_add_5 og test_add_6 vil bli utført og test_add_6 vil rapportere feil med tilbakesporing mens test_add_5 består
Utfør testen med py.test test_addition.py -v og se resultatet
test_addition.py::test_add_1 SKIPPED test_addition.py::test_add_2 SKIPPED test_addition.py::test_add_3 XPASS test_addition.py::test_add_4 xfail test_addition.py::test_add_5 PASSED test_addition.py::test_add_6 FAILED ============================================== FAILURES ============================================== _____________________________________________ test_add_6 _____________________________________________ def test_add_6(): > assert 3+2 == 6,"failed" E AssertionError: failed E assert (3 + 2) == 6 test_addition.py:24: AssertionError ================ 1 failed, 1 passed, 2 skipped, 1 xfailed, 1 xpassed in 0.07 seconds =================
Resultater XML
Vi kan lage testresultater i XML-format som vi kan mate til Continuous Integration-servere for videre behandling og så. Dette kan gjøres ved
py.test test_sample1.py -v –junitxml="result.xml"
Resultatet.xml vil registrere testkjøringsresultatet. Finn et eksempelresultat.xml nedenfor
<?xml version="1.0" encoding="UTF-8"?> <testsuite errors="0" failures="1" name="pytest" skips="0" tests="2" time="0.046"> <testcase classname="test_sample1" file="test_sample1.py" line="3" name="test_file1_method1" time="0.001384973526"> <failure message="AssertionError:test failed because x=5 y=6 assert 5 ==6"> @pytest.mark.set1 def test_file1_method1(): x=5 y=6 assert x+1 == y,"test failed" > assert x == y,"test failed because x=" + str(x) + " y=" + str(y) E AssertionError: test failed because x=5 y=6 E assert 5 == 6 test_sample1.py:9: AssertionError </failure> </testcase> <testcase classname="test_sample1" file="test_sample1.py" line="10" name="test_file1_method2" time="0.000830173492432" /> </testsuite>
Fra vi kan se totalt to tester hvorav en er ikke bestått. Nedenfor kan du se detaljene om hver utførte test under tag.
Pytest Framework Tester en API
Nå skal vi lage et lite pytest-rammeverk for å teste en API. API-en som brukes her er en gratis fra https://reqres.in/. Denne nettsiden er kun for å gi testbar API. Denne nettsiden lagrer ikke våre data.
Her skal vi skrive noen tester for
- liste noen brukere
- logge inn med brukere
Lag filene nedenfor med koden som er gitt
conftest.py – ha en armatur som vil levere base-url for alle testmetodene
import pytest @pytest.fixture def supply_url(): return "https://reqres.in/api"
test_list_user.py – inneholder testmetodene for å liste opp gyldige og ugyldige brukere
- test_list_valid_user tester for gyldig brukerhenting og bekrefter svaret
- test_list_invaliduser tester for ugyldig brukerhenting og bekrefter svaret
import pytest import requests import json @pytest.mark.parametrize("userid, firstname",[(1,"George"),(2,"Janet")]) def test_list_valid_user(supply_url,userid,firstname): url = supply_url + "/users/" + str(userid) resp = requests.get(url) j = json.loads(resp.text) assert resp.status_code == 200, resp.text assert j['data']['id'] == userid, resp.text assert j['data']['first_name'] == firstname, resp.text def test_list_invaliduser(supply_url): url = supply_url + "/users/50" resp = requests.get(url) assert resp.status_code == 404, resp.text
test_login_user.py – inneholder testmetoder for å teste påloggingsfunksjonalitet.
- test_login_valid tester det gyldige påloggingsforsøket med e-post og passord
- test_login_no_password tester det ugyldige påloggingsforsøket uten å sende passord
- test_login_no_email tester det ugyldige påloggingsforsøket uten å sende e-post.
import pytest import requests import json def test_login_valid(supply_url): url = supply_url + "/login/" data = {'email':'test@test.com','password':'something'} resp = requests.post(url, data=data) j = json.loads(resp.text) assert resp.status_code == 200, resp.text assert j['token'] == "QpwL5tke4Pnpja7X", resp.text def test_login_no_password(supply_url): url = supply_url + "/login/" data = {'email':'test@test.com'} resp = requests.post(url, data=data) j = json.loads(resp.text) assert resp.status_code == 400, resp.text assert j['error'] == "Missing password", resp.text def test_login_no_email(supply_url): url = supply_url + "/login/" data = {} resp = requests.post(url, data=data) j = json.loads(resp.text) assert resp.status_code == 400, resp.text assert j['error'] == "Missing email or username", resp.text
Kjør testen med py.test -v
Se resultatet som
test_list_user.py::test_list_valid_user[1-George] PASSED test_list_user.py::test_list_valid_user[2-Janet] PASSED test_list_user.py::test_list_invaliduser PASSED test_login_user.py::test_login_valid PASSED test_login_user.py::test_login_no_password PASSED test_login_user.py::test_login_no_email PASSED
Oppdater testene og prøv ulike utganger
Sammendrag
I denne PyTest-opplæringen dekket vi
- Installer pytest ved hjelp av pip installasjon pytest=2.9.1
- Enkelt pytest-program og kjør det med kommandoen py.test.
- Påstandsutsagn, assert x==y, vil returnere enten True eller False.
- Hvordan pytest identifiserer testfiler og metoder.
- Test filer som starter med test_ eller slutter med _test
- Testmetoder som starter med test
- py.test-kommandoen vil kjøre alle testfilene i den mappen og undermappene. For å kjøre en bestemt fil kan vi bruke kommandoen py.test
- Kjør et undersett av testmetoder
- Gruppering av testnavn etter understreng matching.py.test -k -v vil kjøre alle testene som har i navnet.
- Kjør test etter markører. Merk testene med @pytest.mark. og kjør testene med pytest -m å kjøre tester merket som .
- Kjør tester parallelt
- Installer pytest-xdist ved å bruke pip install pytest-xdist
- Kjør tester med py.test -n NUM der NUM er antall arbeidere
- Opprette fixturmetoder for å kjøre kode før hver test ved å merke metoden med @pytest.fixture
- Omfanget av en fixturmetode er innenfor filen den er definert.
- En fixturmetode kan nås på tvers av flere testfiler ved å definere den i filen conftest.py.
- En testmetode kan få tilgang til en Pytest-fixtur ved å bruke den som et input-argument.
- Parametriserte tester for å kjøre den mot flere sett med innganger.
@pytest.mark.parametrize(“input1, input2, output”,[(5,5,10),(3,5,12)])
def test_add(input1, input2, output):
hevde inngang1+inngang2 == utgang,”mislyktes”
vil kjøre testen med innganger (5,5,10) og (3,5,12) - Hopp over/xfail tester med @pytets.mark.skip og @pytest.mark.xfail
- Lag testresultater i XML-format som dekker utførte testdetaljer ved å bruke py.test test_sample1.py -v –junitxml="result.xml"
- Et eksempel på pytest-rammeverk for å teste en API