• 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 open funksjon
  • 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 som side_effect gjø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 Exception skriv inn når vi trenger det vi kan mock spesifikke ressurser til å kaste et unntak, og så bruke pytest.raises som 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 with kontekst manager., Når Unntak er reist av funksjonen som kalles innenfor with kontekst manager, all kode etter at det i blokken som er hoppet over.

Fjerne lru_cache

Hvis en funksjon du ønsker å teste har functools.lru_cache dekoratø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_cache gir ekstra funksjoner når decoratoring dine funksjoner, det gir:

  • cache_info
  • cache_clear

Den 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 open funksjon, 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 til open i), 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_id som er en global variabel inne i app.aws modul som vi importerer til å referere til andre steder i vår kode:

I mock.patch eksempel, det er to viktige ting å merke seg:

  1. vi ikke bruke return_value.
  2. 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.object eksempel i stedet.,

grunnen Til eksemplet ovenfor fungerer er fordi vi er innstillingen return_value på vår narr. Fordi dette er en MagicMock hver attributt refererte returnerer en ny mock eksempel (en funksjon eller egenskap du ringe på en mock trenger ikke å eksistere) og så vi kaller made_up_function på returneres mock, og på den nyopprettede mock vi sett de siste return_value til 123.,

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_value tilordne):

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_value for å 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.foo modul:

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-asyncio for å hjelpe til med testing asyncio kode

La oss starte med kode for å bli spottet…

import asyncioasync def sum(x, y): await asyncio.sleep(1) return x + y

Nå 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å:

  1. spec
  2. wrap

Vi kan bruke håne spec funksjonen 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_set som vil heve en AttributeError.,

Dette er beste vist med et eksempel:

wrap parameter 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 open funksjon mye enklere…

create=True param sett på mock.patch betyr at mock.MagicMock tilbake vil ‘automagisk’ opprette noen attributter som er kalt på mock (dette er fordi open funksjon 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.