Ez csak egy tény az élet, mint kód nő végül meg kell kezdeni hozzá gúnyolódás a teszt suite. Ami egy aranyos kis kétosztályos projektként indult, most a külső szolgáltatásokkal beszél, és már nem tesztelheti kényelmesen.
ezért Python hajókunittest.mock
, egy erős része a standard könyvtár stubbing függőségek, gúnyos mellékhatások.
azonban a unittest.mock
nem különösebben intuitív.,
sokszor azon tűnődtem, hogy miért nem működik a go-to receptem egy adott esetben, ezért összeállítottam ezt a cheatsheet – et, hogy segítsek magamnak, mások pedig gúnyolódjanak gyorsan.
a kódpéldákat a cikk Github tárolójában találja. A Python 3.6-ot használom, ha 3.2 vagy annál alacsonyabb értéket használ, akkor a mock
PyPI csomagot kell használnia.,
a példák aunittest.TestCase
osztályok segítségével írhatók le az egyszerűség kedvéért a függőségek nélküli végrehajtásban, de apytest
szinte közvetlenül,unittest.mock
működni fog. Ha egy pytest
felhasználó, bár azt javasoljuk, hogy vessen egy pillantást a kiválópytest-mock
könyvtár.
aunittest.mock
modul középpontja természetesen aMock
osztály., A fő jellemzője egy Mock
tárgy, hogy vissza fog térni, még egy Mock
esetben, ha:
- elérése a tulajdonságok
- hív maga az objektum
Ez az alapértelmezett viselkedés, de nem lehet felülírni más-más módon. Például hozzárendelhet egy értéket egy attribútumhoz a Mock
by:
- hozzárendelheti közvetlenül, mint bármely Python objektumhoz.,
- használja a
configure_mock
módszert egy példányon. - vagy adja át a kulcsszó érveket a
Mock
osztály létrehozása.
felül hívások a teszt, be kell állítania a return_value
ingatlan is elérhető egy kulcsszó érv a Mock
initializer., A Mock
mindig ugyanazt az értéket adja vissza minden hívásnál, ez ismét konfigurálható a side_effect
attribútum használatával is:
- ha minden hívásnál különböző értékeket szeretne visszaadni, hozzárendelhet egy iterable-t a
side_effect
– hoz. - ha kivételt szeretne emelni a modell hívásakor, egyszerűen hozzárendelheti a kivétel objektumot a
side_effect
– hoz.,
ezekkel az eszközökkel most létre csonkok lényegében minden Python objektum, ami jól működik a bemenetek a rendszer. De mi a helyzet a kimenetekkel?
ha CLI programot készít az egész Internet letöltéséhez, akkor valószínűleg nem akarja letölteni az egész internetet minden teszten. Ehelyett elegendő lenne azt állítani, hogy a requests.download_internet
(nem valódi módszer) megfelelőnek nevezték. Mock
praktikus módszereket kínál erre.,
Megjegyzés példánkban assert_called_once
nem sikerült, ez a Mock
> objektumok, rögzítik az összes interakciót velük, majd megvizsgálhatja ezeket a kölcsönhatásokat.
például a call_count
a Mock
hívások számának lekéréséhez, valamint a vagy call_args_list
az utolsó vagy az összes hívás argumentumainak ellenőrzéséhez.,
Ha ez bármikor kényelmetlen, használhatja areset_mock
módszert a rögzített interakciók törléséhez, vegye figyelembe, hogy a konfiguráció nem kerül visszaállításra, csak a kölcsönhatások.
végül hadd mutassam be a MagicMock
, a Mock
alapértelmezett mágikus vagy Dunder módszerek. Így aMagicMock
ideális az osztály viselkedésének gúnyolódásához, ezért ez az alapértelmezett osztály a javításkor.,
most már készen állunk arra, hogy elkezdjük gúnyolni és elkülöníteni az egységet a tesztek alatt. Íme néhány recept, amelyet szem előtt kell tartani:
javítás az importáláshoz
aunittest.mock
a vizsgált modul importjának javítása apatch
funkció használatával.
patch
elfogja a import
egy karakterlánc által azonosított állításokat (erről bővebben később), és visszaadja a Mock
példány a fent tárgyalt technikák segítségével előre konfigurálható.,
képzeljük el, hogy tesztelni akarjuk ezt a nagyon egyszerű funkciót:
Megjegyzés importálunkos
ésgetcwd
az aktuális munkakönyvtár megszerzéséhez. Nem akarjuk, hogy valóban hívja a tesztek, bár mivel ez nem fontos, hogy a kód, valamint a visszatérési érték eltérhet környezetek fut.
mint már említettük, meg kell adnunk a patch
karakterláncot, amely az adott importunkat képviseli., Nem akarjuk, hogy a kínálat egyszerűen os.getcwd
mivel ez patch azt az összes modul , ehelyett azt akarjuk, hogy a kínálat a modul teszt import
a os
, azaz work.os
. Amikor a modult importálják patch
működni fog a mágiája, és visszaadja a Mock
helyett.,
Alternatív megoldásként a , vegye figyelembe , hogy a tesztnek van egy extra paramétere: , amelyhez a Mock
injekciót kell beadni a vizsgálatba.,
patch
továbbítja kulcsszó érveket, hogy a Mock
osztály, így beállítani egy return_value
egyszerűen hozzá, mint egy:
Gúnyos osztályok
Ez elég gyakori, hogy a javítás osztályok teljesen vagy részben., with "db"
Worker
visszaadja a Worker
teljes elszigeteltségben meg kell javítanunk az egészet Helper
osztály:
id=”f0f673ce97″>a példában egyszerűen a MockHelper.get_path.return_value
használata nem működik, mivel a kódban get_path
egy példányon, nem maga az osztály.,
a láncolás szintaxisa kissé zavaró, de ne feledje MagicMock
visszaad egy másik MagicMock
hívásokon __init__
. Itt állítunk be minden hamis Helper
példányokat, amelyeket a MockHelper
hozott létre, hogy visszaadja azt, amit a get_path
hívásokra várunk, ami az egyetlen módszer, amellyel törődünk a tesztünkben.,
Class speccing
aMock
rugalmasságának következménye az, hogy ha egyszer kigúnyoltunk egy osztály Python nem fog emelni AttributeError
mivel egyszerűen visszaadja a MagicMock
új példányait. Ez általában egy jó dolog, de vezethet néhány zavaró viselkedés, valamint a potenciálisan hibákat. Például az alábbi írás teszt,
majd csendben át, nincs figyelmeztetés teljesen eltűnt a elírás assrt_called_once
.,
Továbbá, ha nevezze át a Helper.get_path
, hogy a Helper.get_folder
, de felejtsd el, hogy frissítse a hívás a Worker
a vizsgálatok még át:
Szerencsére Mock
jön egy eszköz, hogy megakadályozzák ezeket a hibákat, speccing.
egyszerűen fogalmazva, előre konfigurálja a gúnyokat, hogy csak a spec osztályban ténylegesen létező módszerekre reagáljon., A specifikációk meghatározásának számos módja van, de a legegyszerűbb a autospec=True
patch
hívásra átadni, amely konfigurálja a Mock
hogy úgy viselkedjen, mint az objektum, amelyet gúnyolnak, kivételeket emelve a hiányzó attribútumokra és a helytelen aláírásokra, szükség szerint., Például:
Részleges osztály gúnyos
Ha kevésbé hajlamosak a vizsgálat teljes elszigeteltségben is részben patch egy osztály a patch.object
:
Itt patch.object
, amely lehetővé teszi számunkra, hogy konfigurálása kigúnyolta változata get_path
csak, így a többi magatartás érintetlen., Természetesen ez azt jelenti, hogy a teszt már nem az, amit szigorúan egy egységtesztnek tartana, de lehet, hogy rendben van ezzel.
beépített függvények és környezeti változók
az előző példákban elhanyagoltuk egyszerű osztályunk egy bizonyos aspektusának tesztelését, a print
hívás. Ha az alkalmazás összefüggésében ez fontos, mint például egy CLI parancs, akkor állításokat kell tennünk a hívás ellen.,
print
természetesen egy beépített funkció a Python-ban, ami azt jelenti, hogy nem kell importálnunk a modulunkba, ami ellentétes azzal, amit fent tárgyaltunk az Importálás javításáról., Még mindig tudom képzelni, mi volt ez kissé bonyolultabb változata a funkció:
lehet írni egy teszt, mint a következő:
Megjegyzés: néhány dolgot:
- mi ál
print
nem baj, majd azt állítja, volt egy hívás a következő a “patch import” szabály. Ez azonban a 3-ban bevezetett változás volt.,5, korábban hozzá kellett adniacreate=True
apatch
hívja a jeletunittest.mock
hozzon létre egyMock
annak ellenére, hogy nem importálja az azonosítót. - a
patch.dict
– t használjuk egy ideiglenes környezeti változó beadására aos.environ
– ban, ez kiterjeszthető bármely más szótárra, amelyet ki szeretnénk gúnyolni., - több
patch
context manager hívást is használunk, de csak aas
használatával, mivel ez az, amelyet aassert_called_once_with
hívásához kell használni .,
Ha nem szereti a fészkelő összefüggésben vezetők azt is írni, hogy a patch
hívások a lakberendező formában:
Megjegyezzük azonban, hogy a sorrendben az érvek, hogy a vizsgálat megegyezik a kötegelés parancs a lakberendezők, valamint az is, hogy a patch.dict
nem adja be érv.,ez nagyon gyakori eset:
persze lehet, adjunk hozzá egy tényleges lámpatest fájlt, de a való világ esetekben lehet, hogy nem egy lehetőség, hanem azt, hogy a város a helyi menedzser kimenetet egy StringIO
tárgy:
Nincs semmi különleges, csak a mágikus __enter__
módszer, csak ne felejtsük, hogy a mögöttes mechanika összefüggésben vezetők, valamint néhány okos használja a megbízható MagicMock
.,
gúnyos osztály attribútumok
számos módja van ennek elérésére, de néhány bolondabb bizonyíték arra, hogy mások. Tegyük fel, hogy a következő kódot írta: