• Introducere
  • unittest.,machete sau machete
  • Decorator
  • locul de amplasare a Resurselor
  • Mock return_value vs side_effect
  • Mock Apeluri Imbricate
  • Verificați Excepțiile
  • de Compensare lru_cache
  • Mock Nivel de Modul/Variabile Globale
  • Mock Metodă de Exemplu
  • Mock Metodă de Clasă
  • Bate joc de Întreaga Clasă
  • Mock Asincron Apeluri
  • Mock Tipuri de Exemplu,
  • Mock interna open funcția
  • Concluzie

Introducere

Batjocoritor resurse atunci când scrierea de teste în Python poate fi confuz, dacă nu sunteți familiarizat cu astfel de lucruri., În această postare voi acoperi diverse aspecte ale codului batjocoritor, care sperăm să fie o resursă utilă pentru cei care sunt puțin blocați.

notă: în exemplele de cod folosesc pytest, dar în cea mai mare parte nu ar trebui să conteze.

unittest.mock sau mock

pentru a „mock” o resursă vom avea nevoie mai întâi de modulul mock, iar acesta este primul nostru obstacol: de ce versiune avem nevoie? adică sunt două și ambele par a fi oficiale (mock și unittest.mock).,

mock modulul este compatibil library puteți descărca de PyPy, în cazul în care ca unittest.mock este același lucru, dar compatibil doar cu versiunea de Python pe care îl utilizați.,

Astfel, în aproape toate cazurile, veți dori să-l importe astfel:

import unittest.mock as mock

Pentru mai multe exemple, a se vedea în acest ghid de referință

Decorator

Cel mai comun mod de a bate joc de resurse este de a folosi un Piton decorator jurul funcția de testare:

@mock.patch("thing")def test_stuff(mock_thing): mock_thing.return_value = 123

În acest caz, ceea ce suntem colare (thing) poate fi o variabilă sau o funcție.,

când faceți acest lucru, va trebui să transmiteți un argument funcției dvs. (o puteți numi cum doriți†), care va fi un MagicMock.

Acest lucru înseamnă că, dacă tu nu faci nimic altceva, apoi solicită să thing va (în exemplul de mai sus, cel puțin) rezultat în valoare 123 returnate.

† convenția este de a numi variabilamock_<noun>.,

Dacă îți bați joc de mai multe lucruri, atunci vei stiva mock decoratori ontop de fiecare alte, și trece-le împreună, în scopul de a testa funcția:

@mock.patch("third")@mock.patch("second")@mock.patch("first")def test_stuff(mock_first, mock_second, mock_third): ...

locul de amplasare a Resurselor

este important să știi că atunci când bat joc de tine ar trebui să specificați locația de resurse să fie batjocorit, relevante pentru cazul în care sunt importate., Acest lucru este cel mai bine explicat de exemplu…

Imaginați-vă că am un modul app.foo și, în cadrul modulului de import altă dependență astfel:

from app.bar import thing

s-ar putea crede că, atunci când apelați mock.patch că trece o referință la o resursă ca app.bar.thing. Care ar fi relevantă doar în cazul în care resursa a fost numit cu calea completă în app.foo module (de exemplu, dacă app.foo numit app.bar.thing(...)).,

dacă calea completă a spațiului de nume nu este menționată, ceea ce nu este în exemplul de mai sus (notificare importăm doar resursa thing). Înseamnă că avem nevoie pentru a specifica nume de referință pentru a bate joc ca în cazul în care este importat:

@mock.patch('app.foo.thing')

desi thing există în app.bar vom specifica app.foo.thing ca app.foo este locul unde ne-am importat de utilizare. Acest lucru prinde oameni tot timpul.,

Mock return_value vs side_effect

Dacă funcția are un try/cu excepția cazului în jurul valorii de ea, atunci puteți folosi side_effect pentru că chemarea funcția de a declanșa o Excepție ca valoarea returnată:

@mock.patch('app.aws.sdk.confirm_sign_up', side_effect=Exception('whoops'))

Notă: dacă ai fi folosit return_value=Exception('whoops') apoi mock-ar întoarce reprezentarea șir de Excepție, mai degrabă decât de a ridica o excepție de genul side_effect are.,metoda pe un râs de obiect a fost numit:

motivul pentru acest lucru poate complica și mai mult este din cauza la cum o machetă va reveni cu un nou model, atunci când accesează o proprietate pe o machetă:

codul De mai sus va de eroare:

AssertionError: expected call not found.Expected: listen(8080)Actual: listen(123)

va trebui să asigurați-vă că susțin macheta la momentul potrivit:

Verifica Excepții

Dacă vrem să verifice dacă o bucată de cod aruncă o Exception tip atunci când avem nevoie să ne putem bate joc de anumite resurse pentru a arunca o excepție și de a folosi apoi pytest.raises ca un context manager jurul apelantului de codul nostru de a fi verificate.,

putem prinde și face afirmații împotriva acestui comportament așteptat, batjocorind mai întâi resursa pe care dorim să o aruncăm o excepție și să o facem să arunce propria noastră excepție falsă folosind parametrul side_effect.

Apoi vom specifica exact tipul de excepție ne așteptăm să fie ridicate cu ajutorul pytest.raises(T):

Notă: nu face greseala de a pune orice afirmații în with contextul manager., Odată ce excepția este ridicată de funcția apelată în cadrul managerului de context with, tot codul după el în interiorul blocului este omis.

Compensare lru_cache

Dacă o funcție pe care ați dori să testați are functools.lru_cache decorator aplicate, apoi va trebui să fie conștient de batjocoritor răspunsul care funcționează ca va fi depozitată într-un test și cache rezultatul va fi returnat atunci când apelează funcția din nou pentru a testa un alt comportament (și ar putea confunda când vezi reacția neașteptată).,

Pentru a rezolva această problemă este foarte ușor, pentru că lru_cache oferă funcții suplimentare, atunci când decoratoring funcțiile, se prevede:

  • cache_info
  • cache_clear

acesta Din urmă (cache_clear) este ceea ce ai nevoie pentru a apela. Acest lucru este demonstrat mai jos:

notă: debugging acest lucru nu este întotdeauna evident., Mai târziu, am demonstra cum să batjocorească interna open funcția, și în acest scenariu am dat peste această problemă, pentru că, deși nu-mi băteam joc de nivel superior funcție în sine (am fost batjocoritor apelul la open termen), conținutul din fișierul fiind deschis a fost ceea ce s-a intors si a fi memorate în cache.

Mock Module Level/variabile globale

cu o variabilă modul puteți seta valoarea direct sau utilizațimock.patch.,

În exemplul următor avem variabila client_id care este o variabilă globală în interiorul app.aws module noi de import de referință în altă parte în codul nostru:

În mock.patch de exemplu, există două lucruri esențiale pentru a observa:

  1. nu folosim return_value.
  2. nu există nici o instanță bate joc trecut la funcția de testare.,

Acest lucru este pentru că suntem modifică o variabilă și nu o funcție directă sau ‘nevărsat „” deci, nu este nevoie să treacă o machetă în funcția de testare (dacă doriți să modificați valoarea câteva ori în termen de testul în sine, atunci v-ar bate joc de variabila dar nu imediat atribui o valoare în decorator).

metoda instanței Mock

există mai multe modalități de a realiza batjocura unei metode de instanță., O abordare comună este de a folosi mock.patch.object, astfel:

o Altă abordare este de a bate joc de metoda ca tine ar fi o funcție normală, dar referință metoda prin code:

Alt (deși mai grele dat) abordare pentru batjocorirea o instanță de clasă metodă este de a profita de faptul că o Machetă va reveni un nou bate joc de exemplu atunci când este solicitat:

@mock.patch("foo.bar.SomeClass")def test_stuff(mock_class): mock_class.return_value.made_up_function.return_value = "123"

Notă: în exemplul de mai sus ne-am bate joc de întreaga clasă, care ar putea să nu fie ceea ce vrei. Dacă nu, utilizați exemplul anterior mock.patch.object.,

motivul pentru exemplul de mai sus funcționează, este pentru că suntem setarea return_value pe machete. Pentru că acesta este un MagicMock fiecare atribut referire returnează un nou model instanță (o funcție sau de proprietate suni de pe o macheta nu trebuie să existe) și deci, noi numim made_up_function pe a revenit machete, și pe care recent l-a creat machete ne-am stabilit finală return_value și 123.,dar, după cum sa menționat în nota de mai sus, această abordare ar putea fi un pic prea greu de cap, în funcție de ceea ce sunt nevoile dvs. (indiferent dacă vă pasă dacă aveți o anumită clasă de funcționare sau nu).

metoda clasei Mock

pentru a bate joc de o metodă de clasă este o abordare similară cu batjocorirea unei metode de instanță.,

O abordare ar putea fi faptul că ai bate joc de întreaga clasă (dar acum ai unul mai puțin return_value pentru a atribui):

mock_class.ClassMethodName.return_value = "123"

Sau, mai bine te-ar bate joc de ea ca pe orice funcție normală, dar doar de referință metoda prin clasa:

bate joc de Întreaga Clasă

Pentru a bate joc de o întreagă clasă va trebui să setați return_value să fie o nouă instanță a clasei.,

Vezi alte class legate batjocoritor sfaturi aici

Mock Asincron Apeluri

Batjocoritor cod asincron este, probabil, cel mai confuz aspect al batjocoritor. Soluția mea „Du-te la” voi explica mai întâi, dar după aceea voi împărtăși câteva metode alternative pe care le-am văzut și încercat în trecut.,

în Primul rând ia în considerare acest cod asincron în interiorul unui app.foo modul:

import app.stuffasync def do_thing(x): return await app.stuff.some_concurrent_function(x)

Dacă avem nevoie să își bată joc de coroutine app.stuff.some_concurrent_function, atunci putem rezolva acest lucru prin crearea unei funcții care acționează ca un coroutine și lăsați-l să fie configurabile pentru diferite tipuri de răspunsuri:

Notă: exemplu utilizează tornado pentru funcționare asincron test.,e alternative…

AsyncMock

Notă: aceasta utilizeaza pachetul pytest-asyncio pentru a vă ajuta cu testarea asyncio cod

Să începem cu cod să fie batjocorit…

import asyncioasync def sum(x, y): await asyncio.sleep(1) return x + y

Acum, aici e cum ne-am bate joc de ea…

Maimuță Patch-uri

MagicMock Subclasa

Asincron Funcție Inline

Mock Tipuri de Exemplu,

Când batjocoritor un obiect veți găsi că mock înlocuiește întregul obiect și astfel încât aceasta poate provoca teste pentru a trece (sau nu) în moduri neașteptate.,

Adică, dacă aveți nevoie pentru a face o macheta mai mult ca betonul interfață, atunci există două moduri de a face asta:

  1. spec
  2. wrap

putem folosi macheta e spec caracteristică pentru a imita toate metodele/atribute ale obiectului de a fi batjocorit. Acest lucru asigură că batjocurile dvs. au același api ca și obiectele pe care le înlocuiesc.

Notă: există o mai stricte spec_set care va ridica un AttributeError.,

Acesta este cel mai bine demonstrat printr-un exemplu:

wrap parametru pe de altă parte, vă permite să „spionul” privind punerea în aplicare, precum și afecta comportamentul său.,pe cele de mai sus că își bate joc de obiect întreg, nu doar o singură metodă:

Mock interna a deschide funcția

Python mock biblioteca oferă o abstracție pentru batjocorirea interna open function mult mai simplu…

create=True param setat pe mock.patch înseamnă mock.MagicMock revenit mod automat va crea orice atribute care sunt numite pe machete (acest lucru este pentru că open funcția va încerca să acceseze o mulțime de lucruri diferite și este mai ușor pentru mock să batjocorească tot de asta pentru tine).,

concluzie

acolo vom termina. Sperăm că această listă de tehnici de batjocură vă va putea vedea chiar și prin cele mai complexe coduri care trebuie testate. Lasă-mă să știu ce crezi pe twitter.