, Hogyan kell Futtatni a Unit Tesztek Python Vizsgálat Nélkül A Türelem
Még gyakoribb, mint nem, a szoftver írunk közvetlenül kommunikál, mi a címke, mint a “piszkos” szolgáltatást. Laikus szempontból: olyan szolgáltatások, amelyek kulcsfontosságúak az alkalmazásunk számára, de amelyek kölcsönhatásai szándékoltak, de nem kívánt mellékhatások-azaz nem kívánatosak egy autonóm tesztfutás keretében.,a facebook facebook új funkciójának kipróbálására is készülünk, de nem szeretnénk, ha a tesztcsomagunk futtatásakor tényleg minden alkalommal posztolnánk a Facebookra.
a Pythonunittest
könyvtár tartalmaz egy alcsomagot nevűunittest.mock
—vagy ha nyilvánítja, hogy a függőség, egyszerűenmock
—amely rendkívül erős és hasznos eszköz, amellyel kigúnyolják és csonk ki ezeket a nemkívánatos mellékhatásokat.,
Megjegyzés: mock
újonnan szerepel a standard könyvtár, mint a Python 3.3; előzetes Mockutions kell használni a könyvtár letölthető PyPI.
System Calls vs. Python gúnyos
, hogy egy másik példa, és az egyik, hogy fogunk futni a többi cikk, fontolja meg a rendszer hívásokat., Nem nehéz belátni, hogy ezek a miniszterelnök-jelöltek gúnyolódik: e-forgatókönyvet írsz, hogy vegye ki a CD-meghajtó, egy web szerver, amely eltávolítja elavult cache fájlokat /tmp
, vagy a socket szerver, amely kötődik egy TCP port, ezek a hívások az összes funkció nem kívánt mellékhatások összefüggésben a unit-tesztet.
fejlesztőként jobban érdekli, hogy a könyvtár sikeresen felhívta a CD kiadására szolgáló rendszerfunkciót (a megfelelő argumentumokkal stb.) szemben a ténylegesen tapasztalható a CD-tálca nyitva minden alkalommal, amikor egy teszt fut. (Vagy ami még rosszabb, többször is, mivel több teszt hivatkozik a kiadás kódjára egyetlen egység-teszt futás közben!)
Hasonlóképpen, miközben a unit-teszteket hatékony, nagy teljesítményű azt jelenti, hogy annyi “lassú kód” az automatizált teszt fut, azaz fájlrendszer, illetve a hálózati hozzáférést.,
az első példánkhoz egy szabványos Python teszt esetet az eredeti űrlapról az egyikre refaktálunk a mock
használatával. Bemutatjuk, hogy egy tesztesetünk hogyan teszi okosabbá, gyorsabbá a tesztjeinket, és hogyan tud többet megtudni a szoftver működéséről.
egy egyszerű törlési funkció
mindannyiunknak időről időre törölnie kell a fájlokat a fájlrendszerünkből, ezért írjunk egy funkciót Python-ban, amely kissé megkönnyíti a szkriptek számára.,
#!/usr/bin/env python# -*- coding: utf-8 -*-import osdef rm(filename): os.remove(filename)
nyilvánvaló, hogy a rm
módszerünk ebben az időben nem nyújt sokkal többet, mint az alapul szolgáló os.remove
módszer, de a codebase javulni fog, lehetővé téve számunkra, hogy itt több funkciót adjunk hozzá.
írjunk egy hagyományos tesztesetet, azaz gúnyolódás nélkül:
tesztesetünk nagyon egyszerű, de minden alkalommal, amikor fut, létrehoz egy ideiglenes fájlt, majd törli., Ezenkívül nincs módunk megvizsgálni, hogy a rm
módszerünk megfelelően átadja-e az argumentumot a os.remove
hívásnak. Feltételezhetjük, hogy a fenti teszt alapján teszi, de sok kívánnivalót hagy maga után.
Refactoring with Python Mocks
nézzük refactoring our test case using mock
:
ezekkel a refactorokkal alapvetően megváltoztattuk a teszt működésének módját. Most van egy bennfentes, egy objektum, amelyet felhasználhatunk egy másik funkciójának ellenőrzésére.,
Potenciális Piton Gúnyos Buktatókat
az Egyik első dolog, hogy tartsunk ki, hogy használjuk a mock.patch
módszer, dekoratőr, hogy kigúnyolja az objektum található, mymodule.os
lehetőséget, majd intravénás gúnyt űz a vizsgált esetben a módszer. Nem lenne több értelme, hogy csak gúnyolódni os
maga, ahelyett, hogy a hivatkozás rá mymodule.os
?
nos, Python kissé alattomos kígyó, amikor a behozatali és kezelési modulok., Futásidőben amymodule
modulnak sajátos
van, amelyet a modul saját helyi hatókörébe importálnak. Így ha a os
nevet használjuk, akkor a mymodule
modulban nem fogjuk látni a mock hatásait.
az ismétlődő mantra a következő:
Mock egy elemet, ahol használják, nem, ahol jött.,
Ha ki kell gúnyolni a tempfile
modult myproject.app.MyElaborateClass
, akkor valószínűleg alkalmazni kell a makett myproject.app.tempfile
, mivel minden modul megtartja saját importját.
ezzel a bukással az útból, gúnyolódjunk tovább.
validáció hozzáadása az ” rm “
rm
a korábban definiált módszer meglehetősen leegyszerűsítve. Szeretnénk, ha igazolná, hogy létezik egy elérési út, és egy fájl, mielőtt vakon megpróbálja eltávolítani., Nézzük refactor rm
egy kicsit okosabb:
#!/usr/bin/env python# -*- coding: utf-8 -*-import osimport os.pathdef rm(filename): if os.path.isfile(filename): os.remove(filename)
nagyszerű. Most állítsuk be a teszt esetet, hogy a lefedettség fennmaradjon.
tesztelési paradigmánk teljesen megváltozott. Most már ellenőrizhetjük és érvényesíthetjük a módszerek belső funkcionalitását mellékhatások nélkül.
file-Removal as a Service with Mock Patch
eddig csak a funkciók gúnyolódásával dolgoztunk, de nem olyan objektumokra vagy esetekre vonatkozó módszerekre, ahol a paraméterek küldéséhez gúnyolódás szükséges. Először fedjük le az objektum módszereit.,
a rm
módszer refaktorával kezdjük egy szolgáltatási osztályba. Valójában önmagában nincs szükség arra, hogy egy ilyen egyszerű függvényt egy objektumba ágyazzunk, de ez legalább segít nekünk a mock
kulcsfogalmak bemutatásában. Nézzük refactor:
észre fogod venni, hogy a tesztesetben nem sokat változott:
nagyszerű, így most már tudjuk, hogy a RemovalService
a tervek szerint működik., Hozzunk létre egy másik szolgáltatást, amely függőségnek nyilvánítja:
mivel már van teszt lefedettségünk a RemovalService
, nem fogjuk érvényesíteni a rm
módszer belső funkcionalitását a UploadService
tesztjeinkben. Inkább egyszerűen teszteljük (természetesen mellékhatások nélkül), hogy a UploadService
felhívja a RemovalService.rm
módszert, amelyről tudjuk, hogy “csak works™” a korábbi tesztesetünkből.
ennek két módja van:
- gúnyolja ki a
RemovalService.rm
módszert., - adjon meg egy gúnyos példányt a
UploadService
konstruktorában.
mivel mindkét módszer gyakran fontos az egységtesztelés során, mindkettőt áttekintjük.
1. Lehetőség: Mocking példány módszerek
a mock
könyvtár egy speciális módszer dekoratőr gúnyos objektum példány módszerek és tulajdonságok, a @mock.patch.object
dekoratőr:
nagy! Ellenőriztük, hogy aUploadService
sikeresen hívja példányunkrm
metódusát. Észrevettél valami érdekeset?, A patching mechanizmus valójában felváltotta arm
módszer mindenRemovalService
példányok a vizsgálati módszer. Ez azt jelenti, hogy valóban megvizsgálhatjuk az eseteket. Ha többet szeretne látni, próbáljon betörni egy töréspontot a gúnyos kódban, hogy jól érezze magát a javító mechanizmus működéséről.
Mock Patch Pitfall: Decorator Order
Ha több lakberendezőt használ a tesztelési módszereken, a sorrend fontos, és ez elég zavaró. Alapvetően, amikor a dekorátorokat a módszer paramétereihez térképezi, hátrafelé dolgozik., Tekintsük ezt a példát:
figyeljük meg, hogy paramétereink hogyan illeszkednek a dekorátorok fordított sorrendjéhez? Ez részben azért van, mert a Python működik. Több módszer lakberendezők, itt van az a kivégzés, a pszeudokód:
patch_sys(patch_os(patch_os_path(test_something)))
Mivel a patch sys
a legkülső patch, akkor lehet végrehajtani, múlt, hogy az utolsó paraméter a tényleges vizsgálati módszer érvek. Vegye figyelembe ezt is, majd használja a hibakereső, amikor fut a tesztek, hogy megbizonyosodjon arról, hogy a megfelelő paramétereket fecskendeznek a megfelelő sorrendben.,
2. lehetőség: Mock példányok létrehozása
ahelyett, hogy gúnyolnánk az adott példány módszert, ehelyett csak egy gúnyolt példányt adhatunk meg a UploadService
– nek a kivitelezőjével. Inkább a fenti 1. opciót részesítem előnyben, mivel ez sokkal pontosabb, de sok olyan eset van, amikor a 2.lehetőség hatékony vagy szükséges lehet. Nézzük refactor a tesztet újra:
ebben A példában, még nem is kellett javítás minden funkcionalitás, egyszerűen hozzon létre egy auto-spec a RemovalService
osztály, majd be ebben az esetben a UploadService
, hogy érvényesítse a funkciót.,
amock.create_autospec
módszer funkcionálisan egyenértékű példányt hoz létre a megadott osztályhoz. Ez gyakorlatilag azt jelenti, hogy amikor a visszaküldött példány kapcsolatba kerül, kivételeket fog emelni, ha illegális módon használják. Pontosabban, ha egy módszert rossz számú érvvel hívnak, kivételt emelnek. Ez rendkívül fontos, mivel a refaktorok megtörténnek. Ahogy a könyvtár változik, a tesztek megszakadnak,és ez várható. Automatikus specifikáció használata nélkül a tesztek továbbra is elhaladnak, annak ellenére, hogy a mögöttes megvalósítás megtört.,
mock.Mock
és mock.MagicMock
osztályok
a mock
A könyvtár két fontos osztályt is magában foglal, amelyekre a belső funkcionalitás nagy része épül: és mock.MagicMock
. Ha a választás, hogy egy mock.Mock
példány, a mock.MagicMock
példány, vagy egy auto-spec, mindig előnyben egy auto-spec, mivel segít megőrizni a tesztek épelméjű jövőbeli változások., Ennek oka, hogy amock.Mock
ésmock.MagicMock
minden metódushívást és tulajdonság hozzárendelést Elfogad, függetlenül a mögöttes API-tól. Vegye figyelembe a következő használati esetet:
class Target(object): def apply(value): return valuedef method(target, value): return target.apply(value)
ezt egy mock.Mock
példával tesztelhetjük:
Ez a logika normálisnak tűnik, de módosítsuk a módszer további paraméterek bevitelére:
class Target(object): def apply(value, are_you_sure): if are_you_sure: return value else: return None
futtassa újra a tesztet, majd kiderül, hogy még mindig elhalad. Ez azért van, mert nem a tényleges API-val szemben épül fel., Ezért kell mindig a create_autospec
módszert és a autospec
paramétert használni a @patch
és @patch.object
dekorátorokkal.a Facebook Facebook API-hívásának gúnyolódása
a befejezéshez írjunk egy alkalmazhatóbb valós Python mock példát, amelyet a bevezetőben említettünk: üzenet közzététele a Facebook-ra. Írunk egy szép csomagolóanyagot és egy megfelelő tesztesetet.,
itt van a tesztesetünk, amely ellenőrzi, hogy elküldjük-e az üzenetet anélkül, hogy ténylegesen közzétennénk az üzenetet:
ahogy eddig láttuk, nagyon egyszerű az okosabb tesztek írása a mock
Python-ban.
következtetés
Python mock
könyvtár, ha egy kicsit zavaró dolgozni, egy játék-váltó egység-tesztelés. Már bizonyított közös használata-esetekben a használatbavétel a mock
az egység-vizsgálat, de remélhetőleg ez a cikk segít Python fejlesztők leküzdeni a kezdeti akadályokat, s ír kitűnő, kipróbált kódot.,