Hvordan lapp i Python?

posted in: Articles | 0

Hva er (monkey-)lapp i Python?

(monkey-) lapp er en teknikk for å endre kode atferd uten å endre dens kilde. Det er gjort i runtime, vanligvis av tvingende attributter av eksisterende objekter. Et objekt kan være en forekomst av et eller annet slag, en klasse eller enda en modul. Teknikken er som oftest (mis)brukt til tester når vi ikke kan passere spotter på en enkel måte.

en Annen imponerende eksempel er gevent bibliotek som slår synkron-koden inn i asynkron ved hjelp av monkey-lapp.,

La oss benchmark det ved hjelp av wrk:

Gevent laget ber om en coroutine-vennlig bibliotek og takk til concurrency, det gjorde vårt eksempel server for å håndtere over 13.5 ganger flere forespørsler per sekund.

til slutt, vi har et program som har coroutine-basert concurrency (samme prinsipp som i asyncio eller node.js), men dens kode fortsatt ser ut som en synkron. Vi trenger ikke spesiell, samarbeidende bibliotekene eller async/await søkeord i vår kode. Det er nesten som magi.

Lapp i tester

Python inneholder et verktøy for oppdatering, dvs. unittest.mock.oppdatering., Standard måte å bruke det på, er å dekorere vår test-funksjonen. Anta vi har en Django vise at det ser ut som dette…

og vi ønsker å teste det. Vi legger merke til det har en avhengighet – ApiClient fra en annen modul. Hvis vi ønsker å teste get_stats visning i en forutsigbar og pålitelig måte trenger vi å bruke en test-dobbel i stedet for ApiClient. Det er imidlertid ingen enkel måte å gjøre det på. Hvis det ble vedtatt å get_stats som et argument, så kunne vi bare passere Mock i stedet.,

1
2
3
4

def get_stats(forespørsel, api_client_class):
api_client = api_client_class()
…,

…men det er ikke tilfelle. Vi kan fortsatt bruke patch dekoratør, skjønt!

Dette er ikke slutt ennå, men hvis vi setter en debugger i testen, merker vi at ApiClient.get_stats_for er nå en MagicMock:

Det betyr at våre tentamen var vellykket. Vi byttet ut en problematisk avhengighet med en Narr. Forresten, hvis du ser for beste praksis for bruk av spotter, sjekk ut min (nesten) definitive guide om tentamen i Python eller hvorfor tentamen kan være farlig når det for mye.,

Nå, testen fortsatt er mislykket fordi get_stats mottar en MagicMock mens det forventer en ordbok. Vi trenger å parameterize mock. Vi kan gjøre dette ved å sende et annet argument til @oppdatering:

Patch uten dekoratør

patch kan også brukes som en kontekst manger. En retur vil resultatet bli en Mock blir satt inn i stedet for et attributt blir lappet:

«Python patch ikke fungerer!»– hvordan gjøre det riktig?

noen Ganger vil du møte situasjonen når til tross for tilstedeværelsen av plasteret dekoratør eller sammenheng manager, avhengighet vil se ut som om det ikke var oppdatert i det hele tatt., Kort sagt, det kan være fordi det er flere eksisterende referanser til ting du prøver å lappe. Koden under test bruker det, men du har lappet en annen. Operasjonen var vellykket, men pasienten døde. Hva å gjøre?

kort sagt, du må sørge for at du patch samme referanse som koden under test bruker.

Se der Hvor å patch delen av unittest.mock-dokumentasjonen for mer informasjon. Alternativt, kan du bruke en kjekk liten alternativ til patch, som er patch.gjenstand.

patch.objekt – enklere å få det til høyre

patch.,objektet er død enkel å bruke – du bare importere objekt hvis egenskap du ønsker å oppdatere og bruke patch.objekt:

Hvis du ønsker å bruke patch.objektet for en metode, kan du importere en klasse. Hvis du ønsker å patch.objektet en funksjon eller hele klassen, importere modulen de lever i.

Bør du lappen?

(monkey-) lapp bør brukes sparsomt. Det bør være siste utvei. I koden min, jeg har ingen andre valg, men patch takk til avhengighet injeksjon.

På lang sikt pris for slike triks er veldig, veldig høy., Oppdatering ofte betyr å berøre, og endre gjennomføring detaljer på en måte som ikke var forutsett av forfatterne. Dette introduserer ekstra kopling med ting som ikke bør ha det. Det betyr at de vil være vanskeligere å endre.

Hvis du virkelig må, patch bare public API på et bibliotek eller en modul i koden din.

Legg igjen en kommentar

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