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 pytestfelhaszná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 aconfigure_mock módszert egy példányon.
  • vagy adja át a kulcsszó érveket aMock 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_valuehaszná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:

    1. 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 adnia create=True a patch hívja a jelet unittest.mockhozzon létre egy Mock annak ellenére, hogy nem importálja az azonosítót.
    2. a patch.dict – t használjuk egy ideiglenes környezeti változó beadására a os.environ – ban, ez kiterjeszthető bármely más szótárra, amelyet ki szeretnénk gúnyolni.,
    3. többpatch 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:

    kétféle módon tesztelheti a kódot:

    1. Ha a vizsgált kód aself.ATTRIBUTE, ami ebben a példában van, egyszerűen beállíthatja az attribútumot közvetlenül a példányban. Ez meglehetősen biztonságos, mivel a változás erre az egyetlen példányra korlátozódik.,
    2. Alternatív megoldásként beállíthatja az attribútumot az importált osztályban is a tesztben, mielőtt létrehozna egy példányt. Ez azonban megváltoztatja a teszt során importált osztályattribútumot, amely befolyásolhatja a következő teszteket, ezért emlékeznie kell arra, hogy visszaállítsa azt.

    ennek a nem Mock megközelítésnek a fő hátránya, hogy ha bármikor átnevezi az attribútumot, akkor a tesztek nem fognak sikerülni, és a hiba nem fogja közvetlenül rámutatni erre az elnevezési eltérésre.,

    megoldani, hogy tudjuk használni apatch.object az importált osztály, amely panaszkodik, ha az osztály nem rendelkezik a megadott attribútum.

    itt vannak az egyes vizsgálatok segítségével minden technika:

    gúnyos osztály segítők

    a következő példa a gyökere sok probléma monkeypatching segítségével Mock. Általában olyan érettebb kódbázisokon bukkan fel, amelyek az osztálymeghatározás keretrendszereit és segítőit kezdik használni., Képzelje el például ezt a hipotetikus Field class helper:

    célja egy attribútum becsomagolása és fokozása egy másik osztályban, egy meglehetősen minta, amelyet általában ORMs-ben vagy formában láthat.könyvtárak. Ne foglalkozz túl sokat a részletekkel csak vegye figyelembe, hogy van egy typeés default érték telt el.,

    most vegye be ezt a gyártási kód másik mintáját:

    Ez az osztály aFieldosztályt használja acountryattribútum, amelynek típusastrés adefaultaCOUNTRIES konstans első elemeként. A vizsgált logika az, hogy az országtól függően kedvezményt alkalmaznak.,

    amelyre a következő tesztet írhatjuk:

    de ez nem menne át.,

    menjünk végig a tesztet:

    1. Első foltok az alapértelmezett országok pricer ahhoz, hogy egy lista egyetlen bejegyzés GB ,
    2. Ez kell, hogy a CountryPricer.country attribútum alapértelmezett hogy ez a bejegyzés óta ez a meghatározás magában foglalja a default=COUNTRIES ,
    3. akkor instanciates a CountryPricer, majd kéri a kedvezményes ár GB !

    Tehát mi folyik itt?,

    ennek kiváltó oka a Python viselkedése az importálás során, amelyet legjobban Luciano Ramalho kiváló folyékonyan beszél a 21. fejezetben:

    az osztályok esetében a történet más: importáláskor a tolmács minden osztály testét végrehajtja, még a más osztályokba beágyazott osztályok testét is. Egy osztálytest végrehajtása azt jelenti, hogy az osztály attribútumai és módszerei meg vannak határozva, majd maga az osztályobjektum épül.,

    Alkalmazza ezt a példát:

    1. a country attribútum van Field példány épült a vizsgálat előtt futott a behozatali idő,
    2. Python olvas, a test, a osztály, halad a COUNTRIES meghatározott azon a ponton, hogy a Field például,
    3. A teszt kód fut, de túl késő, hogy patch COUNTRIES, majd a megfelelő állítás.,

    a fenti leírásból megpróbálhatja késleltetni a modul importálását a tesztek belsejébe, például:

    Ez azonban továbbra sem fog átmennimock.patch importálja a modult, majd monkeypatch azt, ami ugyanazt a helyzetet, mint korábban.,

    A munka körül, ezt meg kell ragadnunk, hogy az állam a CountryPricer osztály abban az időben a vizsgálat javítás default a már inicializálva Field például:

    Ez a megoldás nem ideális, mivel ismereteket igényel, a belső a Field ami lehet, hogy nem, vagy szeretné használni, ha a számítógéphez külső könyvtárban, de úgy működik, ez kétségkívül egyszerűsített esetben.,

    Ez az importálási idő kérdése az egyik fő probléma, amellyel a unittest.mockhasználata során találkoztam. Használat közben emlékeznie kell arra, hogy az importálási idő alatt a modulok felső szintjén kód kerül végrehajtásra, beleértve az osztálytesteket is.

    Ha a vizsgált logika ezen logika bármelyikétől függ, akkor lehet, hogy át kell gondolnia, hogyan használja a patch ennek megfelelően.,

    Ez a bevezetés és cheatsheet kell neked gúnyos unittest.mock, de azt javasoljuk, hogy olvassa el a dokumentációt alaposan, van még sok érdekes trükköket tanulni.

    érdemes megemlíteni, hogy vannak alternatívák aunittest.mock, különösen Alex Gaynorpretend könyvtár együttpytest“smonkeypatch lámpatest. Ahogy Alex rámutat, e két könyvtár használatával más megközelítést alkalmazhat, hogy a gúnyolódás szigorúbb, mégis kiszámíthatóbb legyen., Határozottan olyan megközelítés, amelyet érdemes megvizsgálni, de a cikk hatályán kívül esik.

    unittest.mock jelenleg a Python gúnyolódásának szabványa, gyakorlatilag minden kódbázisban megtalálható. Miután egy szilárd megértése segít írni jobb tesztek gyorsabb.

    Articles

    Vélemény, hozzászólás?

    Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük