Che cosa è (scimmia-)patch in Python?
(monkey-) la patch è una tecnica per cambiare il comportamento del codice senza alterarne la sorgente. È fatto in runtime, di solito sovrascrivendo gli attributi degli oggetti esistenti. Un oggetto può essere un’istanza di qualche tipo, una classe o anche un modulo. La tecnica è più comunemente (ab)utilizzata per i test quando non possiamo passare i mock in modo semplice.
Un altro esempio impressionante è la libreria gevent che trasforma il codice sincrono in asincrono usando la patch di scimmia.,
Facciamo un benchmark usando wrk:
Gevent ha reso le richieste una libreria adatta alle coroutine e grazie alla concorrenza, ha permesso al nostro server di esempio di gestire oltre 13,5 volte più richieste al secondo.
Alla fine, abbiamo un programma che ha una concorrenza basata su coroutine (stesso principio di asyncio o node.js) ma il suo codice sembra ancora sincrono. Non abbiamo bisogno di speciali librerie cooperative o parole chiave async / await nel nostro codice. E ‘ quasi come per magia.
Patch nei test
Python include un’utilità per la patch, ad esempio unittest.deridere.patch., Il modo predefinito di usarlo è decorare la nostra funzione di test. Supponiamo di avere una vista Django simile a questa<
e vorremmo testarla. Notiamo che ha una dipendenza-ApiClient da un altro modulo. Se vogliamo testare la vista get_stats in modo prevedibile e affidabile, dobbiamo usare un test-double invece di ApiClient. Tuttavia, non esiste un modo semplice per farlo. Se fosse passato a get_stats come argomento, potremmo semplicemente passare Mock.,
1
2
3
4
|
def get_stats(richiesta, api_client_class):
…
api_client = api_client_class ()
…,
|
…ma non è così. Possiamo ancora usare patch decorator, però!
Questo non è ancora finito, ma se mettiamo un debugger nel test, notiamo che ApiClient.get_stats_for è ora un MagicMock:
Significa che il nostro beffardo ha avuto successo. Abbiamo sostituito una dipendenza problematica con una finta. A proposito, se cerchi le migliori pratiche per l’utilizzo di mock, controlla la mia guida (quasi) definitiva sul mocking in Python o perché il mocking può essere pericoloso quando abusato.,
Ora, il test fallisce ancora perché get_stats riceve un MagicMock mentre si aspetta un dizionario. Dobbiamo parametrizzare la simulazione. Possiamo farlo passando un secondo argomento a @ patch:
Patch senza decoratore
patch può essere utilizzato anche come gestore di contesto. Un risultato di ritorno sarà un Finto inserito in un posto di un attributo che viene patchato:
” La patch Python non funziona!”- come farlo nel modo giusto?
A volte dovrai affrontare la situazione quando, nonostante la presenza di patch decorator o context manager, la dipendenza sembrerà come se non fosse stata patchata affatto., In breve, potrebbe essere perché ci sono più riferimenti esistenti alla cosa che stai cercando di correggere. Il codice in prova ne usa uno, ma ne hai patchato con successo un altro. L’operazione ha avuto successo, ma il paziente è morto. Cosa fare?
In breve, è necessario assicurarsi di applicare lo stesso riferimento utilizzato dal codice in prova.
Vedere Dove patch sezione di unittest.documentazione mock per maggiori dettagli. In alternativa, è possibile utilizzare un’alternativa elegante a patch, cioè patch.oggetto.
patch.object-più semplice per farlo bene
patch.,l’oggetto è morto semplice da usare: basta importare l’oggetto di cui si desidera applicare la patch e applicare la patch.oggetto:
Se si desidera utilizzare patch.oggetto per un metodo, si importa una classe. Se vuoi rattoppare.oggetto una funzione o un’intera classe, importa il modulo in cui vivono.
Si dovrebbe patch?
(monkey-) la patch deve essere usata con parsimonia. Dovrebbe essere la tua ultima risorsa. Nel mio codice, non ho altra opzione che patch grazie all’iniezione di dipendenza.
Nel prezzo a lungo termine per tali trucchi è molto, molto alto., Patch spesso significa toccare e modificare i dettagli di implementazione in un modo che non era previsto dagli autori. Questo introduce un accoppiamento extra con cose che non dovrebbero averlo. Significa che saranno più difficili da cambiare.
Se proprio devi, patch solo l’API pubblica di un’altra libreria o di un modulo nel tuo codice.
Lascia un commento