Vad är (apa-)lapp i Python?
(monkey-) patching är en teknik för att ändra kodbeteende utan att ändra dess källa. Det görs i runtime, vanligtvis genom att åsidosätta attribut för befintliga objekt. Ett objekt kan vara en instans av något slag, en klass eller till och med en modul. Tekniken används oftast (ab) för tester när vi inte kan passera hånar på ett enkelt sätt.
ett annat imponerande exempel är gevent bibliotek som förvandlar synkron kod till asynkron genom att använda monkey-patching.,
låt oss jämföra det med wrk:
Gevent gjorde förfrågningar en coroutine-vänliga bibliotek och tack vare samtidighet, det gjorde vårt exempel server för att hantera över 13,5 gånger fler förfrågningar per sekund.
i slutändan har vi ett program som har coroutine-baserad samtidighet (samma princip som i asyncio eller nod.JS) men koden ser fortfarande ut som synkron. Vi behöver inte speciella, kooperativa bibliotek eller async/väntar nyckelord i vår kod. Det är nästan som magi.
Patch i tester
Python innehåller ett verktyg för lapp, dvs unittest.håna.patch., Standard sättet att använda det är att dekorera vår testfunktion. Antag att vi har en Django-vy som ser ut så här…
och vi skulle vilja testa den. Vi märker att det har ett beroende-ApiClient från en annan modul. Om vi vill testa get_stats-vyn på ett förutsägbart och tillförlitligt sätt måste vi använda en test-dubbel istället för ApiClient. Det finns dock inget enkelt sätt att göra det. Om det skickades till get_stats som ett argument, kunde vi helt enkelt passera Mock istället.,
1
2
3
4
|
Def get_stats(request, api_client_class):
…
api_client = api_client_class()
…,
|
…men så är inte fallet. Vi kan fortfarande använda patch dekoratör, dock!
det här är inte slut än, men om vi lägger en debugger i testet märker vi att ApiClient.get_stats_for är nu en MagicMock:
det betyder att vår mocking lyckades. Vi ersatte ett problematiskt beroende med en Mock. Förresten, om du letar efter bästa praxis för att använda mocks, kolla in min (nästan) definitiva guide om mocking i Python eller varför mocking kan vara farligt när det används för mycket.,
nu misslyckas testet fortfarande eftersom get_stats tar emot en MagicMock medan det förväntar sig en ordbok. Vi måste parametrisera hånet. Vi kan göra det genom att skicka ett andra argument till @patch:
Patch utan dekoratör
patch kan också användas som en kontextmanger. Ett returresultat kommer att vara en Mock som infogas i en plats för ett attribut som patchas:
”Python patch fungerar inte!”– hur man gör det rätt?
Ibland kommer du att möta situationen när beroendet kommer att se ut som om det inte var patchat alls trots närvaron av patch decorator eller context manager., Kort sagt, det kan bero på att det finns flera befintliga referenser till det du försöker lappa. Koden under test använder en, men du lyckades lappa en annan. Operationen var framgångsrik, men patienten dog. Vad göra?
kort sagt måste du se till att du lappar samma referens som koden under test använder.
se var att lappa avsnitt av unittest.håna dokumentation för mer information. Alternativt kan du använda ett snyggt alternativ till patch, det vill säga patch.föremål.
patch.objekt-enklare att få det rätt
patch.,objektet är död enkel att använda – du bara importera objektet vars attribut du vill lappa och tillämpa patch.objekt:
om du vill använda patch.objekt för en metod importerar du en klass. Om du vill lappa.objekt en funktion eller hela klassen, importera modulen de lever i.
ska du lappa ihop?
(apa-) patchning ska användas sparsamt. Det borde vara din sista utväg. I min kod har jag inget annat alternativ än patch tack vare beroendeinjektion.
på lång sikt är priset för sådana knep mycket, mycket högt., Patchning innebär ofta att röra och ändra implementeringsdetaljer på ett sätt som inte förutsågs av författarna. Detta introducerar extra koppling med saker som inte borde ha det. Det betyder att de blir svårare att ändra.
om du verkligen måste, patch endast offentliga API av ett annat bibliotek eller en modul i din kod.
Lämna ett svar