cum să patch-uri în Python?

posted in: Articles | 0

ce este (monkey-)patch-uri în Python?

(monkey-) patching-ul este o tehnică pentru schimbarea comportamentului codului fără a-i modifica sursa. Se face în timpul rulării, de obicei prin atributele imperative ale obiectelor existente. Un obiect poate fi o instanță de un fel, o clasă sau chiar un modul. Tehnica este cel mai frecvent utilizată (ab)pentru teste atunci când nu putem trece batjocurile într-un mod simplu.

Un alt exemplu impresionant este biblioteca gevent care transformă codul sincron în asincron folosind monkey-patching.,

să-l comparăm folosind wrk:

Gevent a făcut cereri o bibliotecă coroutine-friendly și datorită concurenței, a permis serverului nostru exemplu să se ocupe de peste 13,5 ori mai multe cereri pe secundă.

în final, avem un program care are concurență bazată pe coroutină (același principiu ca în asyncio sau nod.js) dar codul său încă arată ca unul sincron. Nu avem nevoie de biblioteci speciale, cooperative sau cuvinte cheie async/wait în codul nostru. E aproape ca prin magie.

Patch în teste

Python include un utilitar pentru patch-uri, adică unittest.batjocură.patch., Modul implicit de utilizare este de a decora funcția noastră de testare. Să presupunem că avem o vedere Django care arată astfel …

și am dori să o testăm. Observăm că are o dependență-ApiClient de la un alt modul. Dacă dorim să testăm vizualizarea get_stats într-un mod previzibil și fiabil, trebuie să folosim un test dublu în loc de ApiClient. Cu toate acestea, nu există o modalitate simplă de a face acest lucru. Dacă a fost trecut la get_stats ca argument, am putea trece pur și simplu Mock în loc.,

1
2
3
4

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

…dar nu este cazul. Putem folosi în continuare patch decorator, deși!acest lucru nu se termină încă, dar dacă punem un depanator în test, observăm că ApiClient.get_stats_for este acum un MagicMock:

înseamnă că batjocura noastră a avut succes. Am înlocuit o dependență problematică cu o batjocură. Apropo, dacă căutați cele mai bune practici pentru utilizarea batjocurilor, consultați ghidul meu (aproape) definitiv despre batjocura în Python sau de ce batjocura poate fi periculoasă atunci când este suprasolicitată.,

acum, testul încă nu reușește, deoarece get_stats primește un MagicMock în timp ce se așteaptă la un dicționar. Trebuie să parametrizăm macheta. Putem face acest lucru prin trecerea unui al doilea argument la @patch:

Patch fără decorator

patch-ul poate fi folosit și ca manager de context. Un rezultat de returnare va fi o machetă introdusă într-un loc al unui atribut care este patch-uri:

„patch-ul Python nu funcționează!– – cum se face corect?uneori vă veți confrunta cu situația când, în ciuda prezenței decoratorului de patch-uri sau a managerului de context, dependența va arăta ca și cum nu ar fi fost patch-uri deloc., Pe scurt, se poate datora faptului că există mai multe referințe existente la lucrul pe care încercați să îl remediați. Codul testat folosește unul, dar ați patch-uri cu succes un alt. Operația a avut succes, dar pacientul a murit. Ce să fac?

pe scurt, trebuie să vă asigurați că patch-uri aceeași referință care utilizează codul în test.

A se vedea în cazul în care pentru a patch-uri secțiune de unittest.documentație mock pentru mai multe detalii. Alternativ, puteți utiliza o alternativă puturos la patch-uri, care este patch-uri.obiect.

plasture.obiect-mai simplu să-l dreapta

patch-uri.,obiect este mort simplu de utilizat-importați doar obiectul al cărui atribut pe care doriți să patch-uri și se aplică patch-uri.obiect:

dacă doriți să utilizați patch-uri.obiect pentru o metodă, importați o clasă. Dacă doriți să patch-uri.obiectează o funcție sau o clasă întreagă, importă modulul în care trăiesc.

ar trebui să vă patch-uri?

(monkey-) patch-uri ar trebui să fie utilizate cu moderație. Asta ar trebui să fie ultima ta soluție. În codul meu, nu am altă opțiune decât patch-ul datorită injecției de dependență.în prețul pe termen lung pentru astfel de trucuri este foarte, foarte mare., Patching-ul înseamnă adesea atingerea și schimbarea detaliilor implementării într-un mod care nu a fost prevăzut de autori. Aceasta introduce cuplarea suplimentară cu lucruri care nu ar trebui să o aibă. Înseamnă că vor fi mai greu de schimbat.

dacă într-adevăr trebuie să, patch-uri numai API publice de o altă bibliotecă sau un modul în codul.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *