- Innledning
- unittest.,mock eller mock
- Dekoratør
- Resource beliggenhet
- Mock return_value vs side_effect
- Mock Nestede Anrop
- Kontroller Unntak
- Fjerne lru_cache
- Mock-Modul Nivå/Globale Variabler
- Mock Eksempel Metode
- Mock Klasse Metode
- Gjør narr av Hele Klassen
- Mock Asynkron Anrop
- Mock Eksempel Typer
- Mock innebygde
openfunksjon - Konklusjon
Innledning
gjør narr av ressurser når du skriver tester i Python kan være forvirrende hvis du er ukjent med å gjøre slike ting., I dette innlegget, jeg kommer til å dekke ulike aspekter av tentamen kode, som forhåpentligvis vil være en nyttig ressurs for de som er litt fast.
Merk: i kode-eksemplene jeg bruker pytest, men for det meste det bør ikke saken.
unittest.mock eller mock
for å «spotte» en ressurs vi må først mock modulen, og dette er vår første snublestein: hvilken versjon trenger vi? det vil si at det er to og de både ser ut til å være offisielle (mock og unittest.mock).,
mock modulen er en bakoverkompatibel biblioteket kan du laste ned fra PyPy, hvor som unittest.mock er det samme, men bare kompatibel med den versjonen av Python du bruker.,
Så i nesten alle tilfeller vil du ønsker å importere det som så:
import unittest.mock as mock
For flere eksempler, se denne reference guide
Dekoratør
Den mest vanlige måten å håne ressurser på, er å bruke en Python-dekoratør rundt teste funksjon:
@mock.patch("thing")def test_stuff(mock_thing): mock_thing.return_value = 123
I dette tilfellet, hva vi er lapp (thing) kan være en variabel eller en funksjon.,
Når du gjør dette vil du trenger for å passere et argument til funksjonen din (du kan kalle det hva du vil,†) som vil være en MagicMock.
Dette betyr at hvis du ikke gjør noe annet, så anrop til thing vil (i eksempelet ovenfor er det i hvert fall) resultatet i verdi 123 returnert.
† konvensjonen er navnet på den variabelen
mock_<noun>.,
Hvis du er som gjør narr av flere ting, da vil du stable mock dekoratører ontop av hverandre, og passere dem sammen for å teste funksjon:
@mock.patch("third")@mock.patch("second")@mock.patch("first")def test_stuff(mock_first, mock_second, mock_third): ...
Resource beliggenhet
Det er viktig å vite at når tentamen må du angi plasseringen av ressurs til å bli spottet, relevant der det er importert., Dette kan best forklares med et eksempel…
Tenk om jeg har en modul app.foo og innenfor denne modulen jeg importere en annen avhengighet som så:
from app.bar import thing
Du tenker kanskje at når du ringer mock.patch at du passerer det en referanse til en ressurs som app.bar.thing. Det ville bare være relevant hvis ressursen ble kalt med at full vei i den app.foo modul (f.eks. hvis app.foo kalt app.bar.thing(...)).,
Hvis det fulle navnet er banen ikke er som det henvises til, som det ikke er i eksempelet ovenfor (legg merke vi importerer bare thing ressurs). Det betyr at vi trenger å angi referanse navneområdet for å håne som hvor det er importert:
@mock.patch('app.foo.thing')
Så selv om thing eksisterer innenfor app.bar vi angi app.foo.thing som app.foo er der vi har importert den for bruk. Dette fanger folk ut hele tiden.,
Mock return_value vs side_effect
Hvis din funksjonen har en prøve/unntatt rundt det, så kan du bruke side_effect for å føre kall på funksjonen til å utløse et Unntak som verdien som returneres:
@mock.patch('app.aws.sdk.confirm_sign_up', side_effect=Exception('whoops'))
Merk: hvis du hadde brukt
return_value=Exception('whoops')så mock ville returnere strengen representasjon av Unntaket heller enn å oppdra et unntak somside_effectgjør.,metoden på en spotte objektet ble kalt:grunnen til At dette kan bli mer komplisert er på grunn av hvordan en mock vil returnere en ny mock når du bruker en eiendom på en mock:
koden ovenfor vil feil:
AssertionError: expected call not found.Expected: listen(8080)Actual: listen(123)Du trenger å gjøre sikker på at du hevde mock til rett tid:
Kontroller Unntak
Hvis vi ønsker å verifisere at noen del av koden kaster en
Exceptionskriv inn når vi trenger det vi kan mock spesifikke ressurser til å kaste et unntak, og så brukepytest.raisessom en kontekst manager rundt den som ringer av våre kode som skal verifiseres.,Vi kan fange og gjøre påstander mot dette forventet atferd ved første tentamen ressurs vi ønsker å kaste et unntak, og få den til å kaste våre egne falske unntak ved bruk av
side_effect– parameteren.Neste vi spesifisere nøyaktig unntak type vi regner med å være hevet ved hjelp av
pytest.raises(T):Merk: du må ikke gjøre den feilen å sette noen påstander innenfor
withkontekst manager., Når Unntak er reist av funksjonen som kalles innenforwithkontekst manager, all kode etter at det i blokken som er hoppet over.Fjerne lru_cache
Hvis en funksjon du ønsker å teste har
functools.lru_cachedekoratør anvendt, så du trenger å være oppmerksom på tentamen svar av den funksjonen som det vil bli mellomlagret i en test og den bufrede resultatet vil bli returnert når du ringer funksjonen igjen for å teste noen andre oppførsel (og kan trolig forvirre deg når du ser uventet reaksjon).,for Å løse dette problemet er veldig enkelt fordi
lru_cachegir ekstra funksjoner når decoratoring dine funksjoner, det gir:
cache_infocache_clearDen siste (
cache_clear) er hva du trenger for å ringe. Dette er demonstrert nedenfor:Merk: debugging dette er ikke alltid åpenbare., Senere på jeg demonstrere hvordan å håne den innebygde
openfunksjon, og i det scenarioet jeg snublet over dette problemet, fordi selv om jeg ikke gjør narr av topp nivå funksjon i seg selv (jeg var tentamen ringe tilopeni), innholdet av filen blir åpnet, var det som ble returnert, og blir bufret.Mock-Modul Nivå/Globale Variabler
Med en modul variabel du kan enten stille inn verdien direkte eller bruke
mock.patch.,I følgende eksempel har vi variabelen
client_idsom er en global variabel inne iapp.awsmodul som vi importerer til å referere til andre steder i vår kode:I
mock.patcheksempel, det er to viktige ting å merke seg:
- vi ikke bruke
return_value.- det er ingen mock eksempel gått til test-funksjonen.,
Dette er fordi vi er å endre en variabel og ikke en direkte funksjon eller ‘callable’ så det er ingen grunn til å passere en mock inn i test-funksjonen (hvis du vil endre verdien et par ganger i løpet av testen i seg selv så ville du gjør narr av den variable, men ikke umiddelbart tilordne en verdi i dekoratør).
Mock Eksempel Metode
Det er flere måter å oppnå harselering av en forekomst metode., En vanlig tilnærming er å bruke
mock.patch.object, for eksempel slik:en Annen tilnærming er å håne den metoden som du ville en normal funksjon, men du refererer til metoden via classname:
en Annen (selv om de er mer tung handed) tilnærming for spottende en klasse forekomst metode er å ta nytte av det faktum at en Mock vil returnere en ny mock eksempel når det heter:
@mock.patch("foo.bar.SomeClass")def test_stuff(mock_class): mock_class.return_value.made_up_function.return_value = "123"Merk: i eksempelet ovenfor vil vi håne hele klassen, som ikke kan være hva du vil. Hvis ikke, så bruk den forrige
mock.patch.objecteksempel i stedet.,grunnen Til eksemplet ovenfor fungerer er fordi vi er innstillingen
return_valuepå vår narr. Fordi dette er enMagicMockhver attributt refererte returnerer en ny mock eksempel (en funksjon eller egenskap du ringe på en mock trenger ikke å eksistere) og så vi kallermade_up_functionpå returneres mock, og på den nyopprettede mock vi sett de sistereturn_valuetil123.,Men som nevnt i ovennevnte notat, denne tilnærmingen kan være litt for sløv avhengig av hva dine behov er (om du bryr deg om du har noen hva som fungerer klasse eller ikke).
Mock Klasse Metode
for Å håne en klasse metoden er en lignende tilnærming til tentamen et eksempel metode.,
En tilnærming kan være at du gjør narr av hele klassen (men nå har du en mindre
return_valuetilordne):mock_class.ClassMethodName.return_value = "123"Eller enda bedre, bør du narr av den som du ville holdt en vanlig funksjon, men bare en referanse til den metoden via klasse:
Mock Hele Klassen
for Å håne en hel klasse du trenger for å sette
return_valuefor å være en ny forekomst av klassen.,Se andre klasse i slekt tentamen tips her
Mock Asynkron Anrop
Tentamen asynkron kode er trolig den mest forvirrende aspekt av tentamen. Min «gå til» – løsning vil jeg forklare først, men etter at jeg vil dele noen alternative metoder jeg har sett og prøvd i det siste.,
Først vurdere dette asynkron kode på innsiden av en
app.foomodul:import app.stuffasync def do_thing(x): return await app.stuff.some_concurrent_function(x)Hvis vi trenger for å håne den coroutine
app.stuff.some_concurrent_function, så vi kan løse dette ved å lage en funksjon som fungerer som en coroutine og at den kan konfigureres for forskjellige typer av svar:Merk: eksempel bruker tornado for å kjøre en asynkron test.,e alternativer…
AsyncMock
Merk: dette utnytter pakken
pytest-asynciofor å hjelpe til med testing asyncio kodeLa oss starte med kode for å bli spottet…
import asyncioasync def sum(x, y): await asyncio.sleep(1) return x + yNå her er hvordan vi skulle håne det…
Monkey Patch
MagicMock Subclass
Asynkron Innebygd Funksjon
Mock Eksempel Typer
Når tentamen et objekt du vil finne at mock erstatter hele objektet, og så kan det føre til testene til å passere (eller mislykkes) på uventede måter.,
Betydning, hvis du trenger å gjøre narr mer som betong grensesnitt, så det er to måter å gjøre det på:
specwrapVi kan bruke håne
specfunksjonen til å etterligne alle metoder/attributter på objektet blir spottet. Dette sikrer din hengivenhet og har samme api som de objektene de erstatter.Merk: det er en strengere
spec_setsom vil heve enAttributeError.,Dette er beste vist med et eksempel:
wrapparameter på den annen side gir deg mulighet til å » spy » på gjennomføringen, samt påvirke sin atferd.,på ovenfor som latterliggjør hele objektet, ikke bare en enkelt metode:Mock innebygde åpne funksjon
Python ‘ s mock-biblioteket gir en abstraksjon for tentamen innebygde
openfunksjon mye enklere…
create=Trueparam sett påmock.patchbetyr atmock.MagicMocktilbake vil ‘automagisk’ opprette noen attributter som er kalt på mock (dette er fordiopenfunksjon vil forsøke å få tilgang til massevis av forskjellige ting, og det er lettere for lissom å håne ut alle at for deg).,Konklusjon
Det vi vil ende. Forhåpentligvis vil denne listen av tentamen teknikker vil være i stand til å se deg gjennom selv de mest komplekse av koden trenger å bli testet. La meg få vite hva du tenker på twitter.