sådan patch i Python?

posted in: Articles | 0

Hvad er (abe -) patching i Python?

(monkey-) lappe er en teknik til at ændre kode adfærd uden at ændre dens kilde. Det gøres i runtime, normalt ved overordnede attributter af eksisterende objekter. Et objekt kan være en forekomst af en slags, en klasse eller endda et modul. Teknikken bruges oftest (ab) til test, når vi ikke kan passere mocks på en enkel måde.

et andet imponerende eksempel er gevent bibliotek, der forvandler synkron kode til asynkron ved hjælp af abe-lappe.,

Lad os benchmark det ved hjælp af wrk:

Gevent lavet anmoder om en coroutine-venligt bibliotek og tak til concurrency, det muligt for vores eksempel-server til at håndtere over 13,5 gange flere forespørgsler per sekund.

i sidste ende har vi et program, der har coroutine-baseret samtidighed (samme princip som i asyncio eller node.js) men dens kode ser stadig ud som synkron. Vi har ikke brug for specielle, kooperative biblioteker eller async/afventer nøgleord i vores kode. Det er næsten som magi.

Patch i test

Python indeholder et værktøj til patching, dvs.unittest.spotte.patch., Standardmetoden til at bruge den er at dekorere vores testfunktion. Antag, at vi har en Django-visning, der ser sådan ud…

, og vi vil gerne teste den. Vi bemærker, at det har en afhængighed-ApiClient fra et andet modul. Hvis vi ønsker at teste get_stats visning på en forudsigelig, pålidelig måde, skal vi bruge en test-dobbelt i stedet for ApiClient. Der er dog ingen enkel måde at gøre det på. Hvis det blev sendt til get_stats som et argument, kunne vi simpelthen passere Mock i stedet.,

1
2
3
4

def get_stats(anmodning, api_client_class):
api_client = api_client_class()
…,

…men det er ikke tilfældet. Vi kan stadig bruge patch dekoratør, selvom!

Dette er ikke slut endnu, men hvis vi sætter en debugger i testen, bemærker vi, at ApiClient.get_stats_for er nu en MagicMock:

det betyder, at vores mocking var vellykket. Vi erstattede en problematisk afhængighed med en Mock. Forresten, hvis du leder efter bedste praksis for at bruge mocks, så tjek min (næsten) endelige guide om mocking i Python eller hvorfor mocking kan være farligt, når overbrugt.,

nu mislykkes testen stadig, fordi get_stats modtager en MagicMock, mens den forventer en ordbog. Vi må parametrisere mocken. Vi kan gøre det ved at sende et andet argument til @patch:

Patch uden dekoratør

patch kan også bruges som en kontekstmanger. Et returresultat vil være en Mock, der indsættes på et sted, hvor en attribut bliver lappet:

“Python patch virker ikke!”–hvordan gør man det rigtigt?

Nogle gange vil du stå over for situationen, når afhængigheden på trods af tilstedeværelsen af patch dekoratør eller Conte .t manager ser ud som om den slet ikke blev lappet., Kort sagt kan det skyldes, at der er flere eksisterende henvisninger til den ting, du forsøger at lappe. Koden under test bruger en, men du har med succes lappet en anden. Operationen var vellykket, men patienten døde. Hvad skal man gøre?kort sagt skal du sørge for at lappe den samme reference, som koden under test bruger.

se hvor du skal lappe sektion af unittest.mock dokumentation for flere detaljer. Alternativt kan du bruge en fiks alternativ til patch, der er patch.genstand.

patch.objekt-enklere at få det rigtige

patch.,objekt er død enkel at bruge – du bare importere det objekt, hvis attribut du ønsker at lappe og anvende patch.objekt:

Hvis du vil bruge patch.objekt for en metode, du importerer en klasse. Hvis du ønsker at lappe.objekt en funktion eller hele klassen, importere det modul, de bor i.

skal du lappe?

(abe-) patching skal bruges sparsomt. Det burde være din sidste udvej. I min kode har jeg ingen anden mulighed end patch takket være afhængighedsinjektion.

på lang sigt er prisen for sådanne tricks meget, meget høj., Patching betyder ofte at røre og ændre implementeringsdetaljer på en måde, som ikke var forudset af forfatterne. Dette introducerer ekstra kobling med ting, der ikke burde have det. Det betyder, at de bliver sværere at ændre.

Hvis du virkelig nødt til, patch kun offentlige API af et andet bibliotek eller et modul i din kode.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *