- Bevezetés
- unittest.,makett, vagy ál
- Lakberendező
- Erőforrás helye
- Mock return_value vs side_effect
- Mock Beágyazott Hívásokat
- Ellenőrizze Kivételek
- Elszámolási lru_cache
- Mock Modul Szint/Globális Változók
- Mock Például Módszer
- Mock Osztály Módszer
- Ál Egész Osztály
- Mock Aszinkron Hívást
- Mock Például Típusok
- Mock beépített openfüggvény
- Következtetés
Bevezető
Gúnyos források írásakor vizsgálatok Python zavaró lehet, ha nincs tisztában vele, hogy ilyen dolgokat., Ebben a bejegyzésben fogom fedezni különböző aspektusait gúnyos kód, amely remélhetőleg hasznos forrás azok számára, akik egy kicsit beragadt.
megjegyzés: a kódpéldákban a pytest-et használom, de a legtöbb esetben nem számít.
unittest.mock vagy mock
 egy erőforrás “mock” – jához először a mock modulra lesz szükségünk, és ez az első botlásunk: melyik verzióra van szükségünk? vagyis kettő van, és mindkettő hivatalosnak tűnik (mockés unittest.mock).,
a mock modul egy visszafelé kompatibilis könyvtár letölthető PyPy, ahol a unittest.mock ugyanaz a dolog, de csak kompatibilis a verzió Python használ.,
Tehát szinte minden esetben azt akarja, hogy importáljuk, így:
import unittest.mock as mocktovábbi lehetőségekért látod, ez a referencia útmutató
Lakberendező
A leggyakoribb módja, hogy kigúnyolja a források használata, a Python lakberendező körül a teszt funkció:
@mock.patch("thing")def test_stuff(mock_thing): mock_thing.return_value = 123ebben Az esetben mi vagyunk folt (thing) lehet egy változó vagy függvény.,
 amikor ezt megteszi, át kell adnia egy argumentumot a funkciójához (megnevezheti azt, amit akar†), amely egy MagicMocklesz.
Ez azt jelenti, hogy ha nem csinálsz mást, akkor a thing hívás (legalább a fenti példában) a 123 értéket eredményezi.
† a
mock_<noun>változó megnevezése.,
Ha több dolgot gúnyol, akkor egymásra rakja a modell dekorátorokat, és átadja őket a tesztfunkcióhoz:
forrás helye
fontos tudni, hogy gúnyolódáskor meg kell adnia a gúnyolódítandó erőforrás helyét, amely releváns a ” P ” funkcióhoz.ahol importálják., Ez a legjobb magyarázható például…
Képzeld el, van egy modul app.foo belül, hogy a modul nem behozatali egy másik függőség, mint így:
from app.bar import thingAzt gondolhatnánk, hogy amikor telefonál mock.patch, hogy át egy hivatkozás, hogy az erőforrás, mint a app.bar.thing. Ez csak akkor lenne releváns, ha az erőforrást a app.foo modulon belüli teljes elérési úttal hívnák (például ha app.foo app.bar.thing(...)).,
 Ha a teljes névtér elérési útja nincs hivatkozva, ami nem szerepel a fenti példában (megjegyzés csak a thing erőforrást importáljuk). Ez azt jelenti, hogy meg kell adnunk a referencia névteret, ahol az importált:
@mock.patch('app.foo.thing')Tehát annak ellenére, hogy thing létezik a app.bar meg kell adnunk app.foo.thing mint app.foo itt importáltuk felhasználásra. Ez elkapja az embereket minden alkalommal.,
Mock return_value vs side_effect
Ha a funkció egy try/except körül, akkor használhatjuk a side_effect okozhat a hívó a funkciót ravaszt Kivételt, mint a visszaadott érték:
@mock.patch('app.aws.sdk.confirm_sign_up', side_effect=Exception('whoops'))Megjegyzés: ha használt volna,
return_value=Exception('whoops')akkor a modell visszatér a string ábrázolása inkább Kivétel, mint felnevelni egy kivétel, mint aside_effectnem.,a módszer egy kigúnyolta tárgy volt a címe, hogy:Az oka, hogy itt még bonyolultabb lesz köszönhető, hogy egy ál visszatér egy új mock elérésekor egy ingatlan egy ál:
A fenti kód error:
AssertionError: expected call not found.Expected: listen(8080)Actual: listen(123)kell, hogy győződjön meg róla, hogy érvényesíthesse a modell a megfelelő pillanatban:
Ellenőrizze Kivételek
Ha szeretnénk ellenőrizni, hogy egy darab kód dob egy
Exceptiontípus, amikor szükségünk van rá, hogy meg tudjuk ál konkrét források dob egy kivételt, akkor használjuk apytest.raisesmint összefüggésben manager körül a hívó fél a kódot ellenőrizni.,tudjuk fogni, és állításokat ez ellen a várható viselkedés először gúnyos erőforrás szeretnénk dobni egy kivételt, és kap, hogy dobja a saját hamis kivétel a
side_effectparaméter.ezután adja meg a pontos kivétel típusa számítunk fel a
pytest.raises(T):Megjegyzés: ne kövesd el azt a hibát, hogy egyetlen állítások belül a
withösszefüggésben menedzser., Miután a kivételt awithkontextuskezelőben hívott függvény emeli, a blokk belsejében lévő összes kódot kihagyja.Elszámolási lru_cache
Ha egy funkciót szeretné, hogy tesztelje a
functools.lru_cachelakberendező alkalmazott, akkor kell figyelnünk a gúnyos válasz, hogy a funkciója, mint ez lesz a gyorsítótárazott egy teszt, valamint a gyorsítótárazott eredmény lesz tért vissza, amikor a függvény hívása újra tesztelni egy másik magatartás (lehet, hogy valószínű, hogy összezavarjon, amikor látod, hogy a váratlan válasz).,a probléma megoldása nagyon egyszerű, mert a
lru_cachetovábbi funkciókat biztosít a funkciók díszítésekor:
cache_info
cache_clearA ez utóbbi (
cache_clear) az, amit fel kell hívnia. Ezt az alábbiakban mutatjuk be:megjegyzés: a hibakeresés ez nem mindig nyilvánvaló., Később bemutatom, hogyan kell kigúnyolni a builtin
openfüggvényt, és ebben a forgatókönyvben belebotlottam ebbe a problémába, mert bár nem gúnyoltam magát a felső szintű függvényt (gúnyoltam aopenwithin), a megnyitott fájl tartalma az volt, amit visszatértek és gyorsítótáraztak.Mock modul szint/globális változók
egy modulváltozóval közvetlenül beállíthatja az értéket, vagy használhatja a
mock.patch.,a következő példa van a változó
client_idami egy globális változó belül aapp.awsmodul importálunk, hogy referencia máshol a kódot:a
mock.patchpélda, van két alapvető dolog, amit észre:
- nem használjuk a
return_value.- nincs álpéldány át a teszt függvény.,
Ez azért van, mert módosítjuk egy változó, nem pedig egy funkció közvetlen vagy ‘lehívható’, tehát nem kell, hogy átmenjen egy ál a teszt funkció (ha meg szeretné változtatni az érték néhány alkalommal belül magát a vizsgálatot, akkor kigúnyolják a változó, de nem azonnal rendel értéket a dekoratőr).
Mock Instance Method
többféle módon lehet elérni egy példány metódus gúnyolódását., Egy közös megközelítés, hogy a
mock.patch.object, valahogy így:egy Másik megközelítés, hogy kigúnyolja a módszer, mint egy normális működését, de a referencia módszer segítségével a classname:
egy Másik (bár keménykezű) megközelítés gúnyos egy osztályban például az a módszer, hogy kihasználják azt a tényt, hogy egy Ál visszatér egy új mock például, amikor címe:
@mock.patch("foo.bar.SomeClass")def test_stuff(mock_class): mock_class.return_value.made_up_function.return_value = "123"Megjegyzés: a fenti példában gúnyoljuk az egész osztály, amely lehet, hogy nem, hogy mit akarsz. Ha nem, akkor használja az előző
mock.patch.objectpéldát.,a fenti példa azért működik, mert a
return_valueértéket állítjuk be a modellünkre. Mert ez egyMagicMockminden attribútum hivatkozott visszatér egy új mock például (egy funkció vagy tulajdonság, egy makett nem létezik), ezért hívjukmade_up_functiona vissza ál, valamint az újonnan létrehozott ál beállítottuk a véglegesreturn_value, hogy a123.,de amint azt a fenti megjegyzés is említi, ez a megközelítés kissé túl tompa lehet, attól függően, hogy mi az Ön igényei (függetlenül attól, hogy érdekel-e valami, ami működik, vagy sem).
Mock Class Method
egy osztály metódus kigúnyolásához hasonló megközelítés.,
az egyik megközelítés az lehet, hogy az egész osztályt kigúnyolja (de most van egy kevesebb
return_value, hogy hozzárendelje):mock_class.ClassMethodName.return_value = "123"vagy még jobb, ha gúnyolódna, mintha bármilyen normális funkció lenne, de csak hivatkozzon a módszerre az osztályon keresztül:
Mock egész osztály
osztály a
return_valueértéket kell beállítania, hogy az osztály új példánya legyen.,lásd a többi osztályhoz kapcsolódó gúnyos tippeket itt
Mock Async hívások
gúnyos aszinkron kód valószínűleg a leginkább zavaró szempont a gúnyolódás. A “go to” megoldásomat először elmagyarázom, de utána megosztom néhány alternatív módszert, amelyeket a múltban láttam és kipróbáltam.,
Először tekintsük ezt aszinkron kód belsejében egy
app.foomodul:import app.stuffasync def do_thing(x): return await app.stuff.some_concurrent_function(x)Ha meg kell ál a coroutine
app.stuff.some_concurrent_function, akkor meg tudjuk ezt oldani azáltal, hogy egy funkció úgy működik, mint egy coroutine, valamint lehetővé teszik, hogy beállítható a különböző típusú válaszok:Megjegyzés: a példában tornádó a futó aszinkron teszt.,e alternatívák…
AsyncMock
Megjegyzés: ezt hasznosítja a csomag
pytest-asyncio, hogy segítsen a vizsgálat asyncio kódkezdjük a kódot, hogy kigúnyolják…
import asyncioasync def sum(x, y): await asyncio.sleep(1) return x + yMost itt van, hogy gúnyolódjon.
Majom Javítás
MagicMock Ns
Aszinkron Inline Függvény
Mock Például Típusok
Ha a gúnyos egy tárgyat fogsz jönni, hogy az ál helyettesíti a teljes objektum, ezért okozhat tesztek át (vagy nem) váratlan módon.,
jelentése, Ha meg kell, hogy egy mock több, mint a Konkrét felület, akkor kétféle módon lehet csinálni, hogy:
spec
wraphasználhatjuk mock
specfunkció, hogy utánozza az összes módszer / attribútumok az objektum gúnyolódik. Ez biztosítja, hogy a gúnyolódásoknak ugyanaz az api-ja legyen, mint az általuk helyettesített objektumoknak.megjegyzés: van egy szigorúbb
spec_set, amely felveti aAttributeError.,ezt legjobban egy példa bizonyítja:
a
wrapparaméter másrészt lehetővé teszi, hogy “kémkedjen” a megvalósításban, valamint befolyásolja annak viselkedését.,a fenti, hogy kigúnyolja az egész tárgy, nem csak egy módszer:Mock beépített nyitva funkció
Python ál könyvtár rendelkezik egy absztrakció gúnyolódik a beépített
openfunkció sokkal egyszerűbb…A
create=Trueparam set amock.patchazt jelenti, hogy amock.MagicMockvissza fog automatikusan hoz létre attribútumok, hogy hívják a mock (ez azért van, mert aopenfunkció elérésére irányuló próbálkozás sok különböző dolgokat könnyebb makett, hogy gúnyold ki, hogy az ön számára).,következtetés
ott véget érünk. Remélhetőleg ez a lista a gúnyos technikák képes lesz látni végig még a legösszetettebb kódot kell vizsgálni. Hadd tudja, mit gondol a Twitteren.