En Introduksjon til Tentamen i Python

Hvordan å Kjøre Unit Tester i Python Uten å Teste Din Tålmodighet

Mer ofte enn ikke, programvaren vi skriver direkte samhandler med hva vi ville label som «skitne» tjenester. I lekmann vilkår: tjenester som er avgjørende for vår søknad, men som vekselsvirkningene har ment, men uønskede bivirkninger—som er uønsket i sammenheng med en autonom testkjøring.,

For eksempel: kanskje vi skriver et sosialt og ønsker å teste ut vår nye «Post til Facebook-funksjon», men ønsker ikke å faktisk legge til Facebook hver gang vi kjører våre test suite.

Python unittest biblioteket har en subpackage navnet unittest.mock—eller hvis du erklærer det som en avhengighet, rett og slett mock—som gir ekstremt kraftig og nyttig middel for å håne og stumpe disse uønskede bivirkninger.,

Merk: mock er nylig inkludert i standard-biblioteket som Python 3.3; før distribusjoner er nødt til å bruke Mock bibliotek nedlastbare via PyPI.

System Anrop vs. Python Tentamen

for Å gi deg et eksempel, og en som vi vil kjøre med for resten av artikkelen, du vurdere systemet anrop., Det er ikke vanskelig å se at disse er gode kandidater for spottende: enten du skriver et skript for å løse ut en CD-rom-stasjon, en web-server som fjerner foreldet cache-filer fra /tmp, eller en socket server som binder seg til en TCP-port, disse samtalene alle har uønskede bivirkninger i forbindelse med din unit-tester.

Som en utvikler, kan du bryr deg mer om at biblioteket vellykket kalt systemet fungerer for å løse ut en CD i motsetning til å oppleve CD-skuffen åpnes hver gang det kjøres en test.,

Som en utvikler, kan du bryr deg mer om at biblioteket vellykket kalt systemet fungerer for å løse ut en CD (med det riktige argumenter, etc.) i motsetning til å faktisk opplever CD-skuffen åpnes hver gang det kjøres en test. (Eller enda verre, flere ganger, som flere tester referanse eject koden under en enkelt enhet-test run!)

på samme måte, å holde din unit-tester effektiv og effektivt betyr å holde så mye «slow-koden» ut av den automatiske testen kjøres, nemlig filsystem og tilgang til nettverk.,

For vårt første eksempel, vil vi refactor en standard Python-test fra opprinnelige form til en bruker mock. Vi vil vise hvordan å skrive en test med spotter vil gjøre våre tester smartere, raskere, og i stand til å avsløre mer om hvordan programvaren fungerer.

En Enkel Slette Funksjon

Vi trenger alle å slette filer fra vår filsystem fra tid til annen, så la oss skrive en funksjon i Python som vil gjøre det litt lettere for våre skript til å gjøre det.,

#!/usr/bin/env python# -*- coding: utf-8 -*-import osdef rm(filename): os.remove(filename)

Selvfølgelig, vår rm metode på dette tidspunkt ikke gi mye mer enn den underliggende os.remove metode, men våre codebase vil forbedre, slik at vi kan legge til mer funksjonalitet her.

La oss skrive en tradisjonell test case, dvs., uten spotter:

Vår test er ganske enkel, men hver gang det kjøres en midlertidig fil som er opprettet og deretter slettet., I tillegg, vi har ingen måte å teste om vår rm metoden på riktig måte går argumentet ned til os.remove anrop. Vi kan anta at det ikke er basert på testen over, men mye som er igjen å være ønsket.

Refactoring med Python Spotter

La oss refactor våre test ved hjelp av mock:

Med disse refactors, vi har fundamentalt endret måten at testen fungerer. Nå har vi en insider, et objekt som vi kan bruke til å kontrollere funksjonaliteten til en annen.,

Potensial Python Tentamen Fallgruver

En av de første ting som stikker seg ut er at vi bruker mock.patch metode dekoratør for å håne et objekt som ligger på mymodule.os, og injisere at mock inn i vår test case-metoden. Ville det ikke være mer fornuftig å bare mock os seg selv, snarere enn som en referanse til det på mymodule.os?

Vel, Python er litt av en sleipe slange når det kommer til import og administrere moduler., Ved kjøring, mymodule modulen har sin egen os som er importert inn i sin egen lokale omfang i modulen. Dermed, hvis vi mock os vi ikke til å se effekten av mock i mymodule modulen.

mantraet for å holde gjentakende, er dette:

Mock et element der den er brukt, ikke hvor det kom fra.,

Hvis du trenger å håne tempfile modulen for myproject.app.MyElaborateClass, har du sannsynligvis trenger å bruke mock til myproject.app.tempfile, som hver modul holder sin egen import.

Med at fallgruven ut av veien, la oss holde tentamen.

Legge til Validering for å ‘rm’

rm metode definert tidligere er ganske oversimplified. Vi ønsker å ha det validere at en bane eksisterer og er en fil før du blindt forsøker å fjerne det., La oss refactor rm for å være litt smartere:

#!/usr/bin/env python# -*- coding: utf-8 -*-import osimport os.pathdef rm(filename): if os.path.isfile(filename): os.remove(filename)

Flott. Nå, la oss justere våre test for å holde dekning opp.

Vår testing paradigmet har helt forandret. Vi kan nå bekrefte og validere interne funksjonaliteten av metoder og uten bivirkninger.

Fil-Fjerning som en Tjeneste med Mock Patch

Så langt, vi har bare jobbet med å levere spotter for funksjoner, men ikke for metoder på objekter eller tilfeller der tentamen er nødvendig for å sende parametere. La oss dekke objekt metoder først.,

Vi vil begynne med a refactor av rm metoden inn i en tjeneste klasse. Det er virkelig ikke et saklig behov, per se, til å kapsle inn slik en enkel funksjon til et objekt, men det vil i det minste hjelpe oss å demonstrere sentrale begreper i mock. La oss refactor:

Du vil legge merke til at ikke mye har forandret seg i vår test:

Flott, så vet vi nå at RemovalService fungerer som planlagt., La oss lage en annen tjeneste som erklærer det som en avhengighet:

Siden vi allerede har test-dekning på RemovalService, vi kommer ikke til å validere interne funksjonaliteten av rm metode i våre tester av UploadService. Nei, vi skal bare prøve (uten bivirkninger, selvfølgelig) som UploadService anrop RemovalService.rm metode, som vi vet «bare fungerer™» fra vår forrige test.

Det er to måter å gå om dette:

  1. Mock ut RemovalService.rm metoden i seg selv.,
  2. Levere en spotte eksempel i konstruktøren av UploadService.

Som begge metodene er ofte viktig i en unit-test, vi gjennom begge.

Alternativ 1: Tentamen Eksempel Metoder

mock biblioteket har en spesiell metode som dekoratør for tentamen objekt eksempel metoder og egenskaper, @mock.patch.object dekoratør:

Flott! Vi har kontrollert at UploadService vellykket samtaler vårt eksempel er rm metode. Legger merke til noe interessant i det?, Den lapp mekanisme faktisk erstattet rm metode for alle RemovalService forekomster i vår test metode. Det betyr at vi faktisk kan inspisere forekomster seg selv. Hvis du ønsker å se mer, kan du prøve å slippe i et stoppunkt i din tentamen-koden for å få en god følelse for hvordan lapp mekanismen fungerer.

Mock Patch Fallgruven: Dekoratør For

Når du bruker flere dekoratører på test metoder, rekkefølgen er viktig, og det er litt forvirrende. I utgangspunktet, når kartlegging dekoratører til metode parametre, jobbe bakover., Se på dette eksempelet:

Merke til hvordan våre parametre er matchet til motsatt rekkefølge av dekoratører? Det er delvis på grunn av måten Python fungerer. Med flere metode dekoratører, her er rekkefølgen for gjennomføring i pseudocode:

patch_sys(patch_os(patch_os_path(test_something)))

Siden oppdateringen til sys er det ytterste oppdateringen, vil det bli utført siste, noe som gjør det til den siste parameteren i selve testmetoden argumenter. Ta notat av dette godt og bruk en debugger når du kjører tester for å sikre at de riktige parametrene blir injisert i riktig rekkefølge.,

Alternativ 2: Lage Mock Tilfeller

i Stedet for tentamen konkrete tilfellet metode, kunne vi i stedet bare gi en spotte eksempel til UploadService med sin konstruktør. Jeg foretrekker alternativ 1 ovenfor, som det er en mye mer presis, men det er mange tilfeller der alternativ 2 kan være effektiv eller nødvendig. La oss refactor våre test igjen:

I dette eksemplet, vi har ikke engang hadde å lappe noe funksjonalitet, vi bare lag en auto-spec for RemovalService klasse, og deretter injisere dette tilfellet i vår UploadService for å validere funksjonalitet.,

mock.create_autospec metoden oppretter et tilsvarende eksempel gitt klasse. Hva dette betyr, praktisk talt, er at når de kom tilbake eksempel er samhandlet med, det vil heve unntak hvis det er brukt i ulovlige måter. Mer spesifikt, hvis en metode som er kalt med feil antall argumenter, et unntak vil bli hevet. Dette er ekstremt viktig som refactors skje. Som et bibliotek endringer, tester pause, og det er forventet. Uten å bruke en auto-spec, våre tester vil fortsatt bestå, selv om den underliggende gjennomføring er brutt.,

Eksempel: mock.Mock og mock.MagicMock Klasser

mock biblioteket inneholder også to viktige klasser på som mest av den interne funksjonaliteten er bygget på: mock.Mock og mock.MagicMock. Når det er gitt et valg om å bruke en mock.Mock eksempel mock.MagicMock eksempel, eller en auto-spec, alltid favorisere bruke en auto-spec, som det bidrar til å holde tester tilregnelig for fremtidige endringer., Dette er fordi mock.Mock og mock.MagicMock godta alle metode samtaler og eiendom oppdrag uavhengig av underliggende API. Vurder følgende use case:

class Target(object): def apply(value): return valuedef method(target, value): return target.apply(value)

Vi kan teste dette med en mock.Mock eksempel slik:

Denne logikken virker fornuftig, men la oss endre Target.apply metode for å ta flere parametre:

class Target(object): def apply(value, are_you_sure): if are_you_sure: return value else: return None

kjør testen, og du vil finne at det fortsatt går. Det er fordi det ikke er bygget mot den faktiske API., Dette er grunnen til at du alltid bør bruke create_autospec metode og autospec parameter med @patch og @patch.object dekoratører.

Python Mock Eksempel: Tentamen en Facebook API-Kall

Til slutt opp, la oss skrive en mer gjeldende i den virkelige verden python mock eksempel, som vi nevnte i innledningen: å poste en melding til Facebook. Vi skal skrive en fin wrapper-klasse og en tilsvarende test.,

Her er vår test, som sjekker at vi legger ut meldingen uten egentlig å poste meldingen:

Som vi har sett så langt, det er veldig enkelt å begynne å skrive smartere tester med mock i Python.

Konklusjon

Python ‘ s mock biblioteket, hvis det er litt forvirrende å jobbe med, er en spill-veksler for unit-testing. Vi har vist vanlig bruk-tilfeller for å komme i gang ved hjelp av mock i unit-testing, og forhåpentligvis vil denne artikkelen vil hjelpe Python utviklere overvinne den første hekk og skrive gode, testet koden.,

Share

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *