Piton gúnyos van valami unintuitive rólad. Nem könnyű megbirkózni veled, és több ” Ah, most már értem!”pillanatok, mielőtt jobban megértenéd., Ön egy hatékony, fantasztikus eszköz, amely lehetővé teszi az automatizált egység tesztek, de tudom, hogy sok fejlesztő, aki “get by” a tudás van, és írásban ezeket a teszteket hosszabb időt vesz igénybe, mint kellene.
sok cikk van a gúnyolódásról, és igen, most írok egy másikat. Azonban, nagyon szeretnék egy go egyértelműen elmagyarázza, különösen azok ” Aha!”pillanatok, amelyek előmozdították a megértésemet.
először is, mi a gúnyolódás? Itt van egy idézet a docs:
mock egy könyvtár tesztelés Python., Ez lehetővé teszi, hogy cserélje ki részei a rendszer teszt alatt ál objektumok, valamint, hogy állításokat arról, hogyan használták őket.
tehát “lehetővé teszi a rendszerek alkatrészeinek cseréjét”, de milyen alkatrészeket? Kiderül, hogy nagyjából bármit meg lehet határozni, például:
- funkciók
- osztályok
- objektumok
helyettesíted őket “mock objektumokkal”, amelyek a Mock vagy a MagicMock osztály példányai.,
ezután “állításokat készít” az Álpéldányról, ami annak ellenőrzésére szolgál, hogy a Modellpéldányt a várt módon használták-e.
ebben a cikkben a rendszerek alkatrészeinek cseréjének alapjait fogom lefedni, de nem fogom fedezni az állítások készítését.
kezdjük egy egyszerű példával. Megyek, hogy hozzon létre egy új modul neve simple.py ebben a modulban meg fogok határozni egy simple_function nevű függvényt, amely csak egy ilyen karakterláncot ad vissza:
def simple_function():
return "You have called simple_function"
most létrehozok egy második modult, az úgynevezett use_simple.py., Ebben a modulban fogok importálni a mock csomagot unittest és importálja az egyszerű modul:
from unittest import mockimport simple
következő megyek egy írási két funkció, az egyik, hogy felhívja simple_function általában és az egyik, hogy gúnyolódik a hívást, hogy azt. Vegye figyelembe, hogy általában ezt tesztelési összefüggésben tenné, de szándékosan eltávolítom ezt, hogy a gúnyos részre összpontosíthassak. Az első függvény:
def use_simple_function():
result = simple.simple_function()
print(result)use_simple_function()
amint láthatja, csak kiírja a simple_function eredményét., Pontosabban, a kimenet:
You have called simple_function
a második funkcióhoz simple_function-t fogok használni.patch lakberendező. Ez a lakberendező lehetővé teszi annak megadását, hogy mit szeretne gúnyolni, ha átadja egy karakterláncot a “csomag” formátumban.modul.FunctionName’., A példánkban nincs csomag, de a modult egyszerűnek nevezzük, a funkciót pedig simple_function-nek, így a dekorátor így fog kinézni:
@mock.patch('simple.simple_function')
ezután meg kell írnunk a második funkciónkat:
@mock.patch('simple.simple_function')
def mock_simple_function():
mock_simple_function, de bármit nevezhetünk. Itt hiányzik egy paraméter, mert amikor egy funkciót díszít @mock.patch ez adja át egy példányát a MagicMock osztály (egy MagicMock objektum), hogy használják, hogy cserélje ki a funkciót gúnyolódik., Így fog kinézni:
@mock.patch('simple.simple_function')
def mock_simple_function(mock_simple_func):
tehát @mock megadásával.patch (‘egyszerű.simple_function’) azt mondom, hogy a simple_func-ot a mock_simple_func nevű paraméterhez rendelt MagicMock objektummal akarom helyettesíteni.
kezdetben húzzuk ki a funkciót a mock_simple_func kinyomtatásával, majd hívjuk:
futtatáskor a kimenet:
<MagicMock name='simple_function'>
, amely egy magicmock objektum, amelyet a simple_function helyett hívunk., Fontos megjegyezni, hogy az objektum név attribútuma a gúnyolódás, az azonosító pedig az objektum egyedi száma.
Ha most is nyomtassa ki simple_function (de nem hívja meg):
amely termel a kimenet:
<MagicMock name='simple_function'>
<MagicMock name='simple_function'>
láthatjuk, hogy a megfelelő azonosítók mock_simple_func ugyanaz MagicMock objektum, mint simple_function.
eddig jó. Kigúnyoltuk simple_function. Ahhoz, hogy explicit, simple_function már kigúnyolták, mert helyébe egy MagicMock objektum.,
adjuk hozzá a sorokat az első függvényből:
futtatáskor a kimenet:
amint az a kimenet harmadik sorából látható, amikor a simple_function-t ténylegesen hívják, más MagicMock objektumot hoz létre. Ne feledje, hogy mivel a simple_function-t kigúnyoltuk, valójában egy MagicMock objektum, tehát amikor simple_function-nek hívjuk, valójában a MagicMock objektumot hívjuk!
számomra ez az, ahol a zavart beállít.
- miért jön létre egy új MagicMock objektum?
- és hogy a földön lehet hívni egy objektumot egyébként?, Általában “TypeError:” * * * * “objektum nem hívható”, amikor megpróbálja.
szüneteljünk egy percig, hogy jobban megnézzük a MagicMock-ot.
a Magicmocknak mágiája van a nevében, mert a legtöbb Python mágikus módszer alapértelmezett megvalósításával rendelkezik. Mi a Python mágikus módszer, amit kérdezel? Ez az összes speciális Python funkciók, amelyek kettős aláhúzás elején és végén a nevüket. Ezek listáját itt találja. Az egyik érdekes itt __call__., A hívás funkció le, mint:
Hívják, amikor egy objektum neve, mint egy függvény
ha egy osztály megvalósítja ezt a funkciót hozhat létre az osztály példánya, majd hívja, hogy például egy függvény, azaz :
Ezért, amikor MagicMock az úgynevezett mint egy funkció, a __hívás__ funkció neve. MagicMock végrehajtása ezt a funkciót létrehoz egy új mock!
tehát amikor simple_function () – nak hívjuk, egy új mock jön létre, majd visszatér. Nem csak ez, hanem a szülő és a gyerek kigúnyolása is., Amikor az egyik ál létrehoz egy másikat, akkor a szülő lesz, az újonnan létrehozott pedig a gyermek. Az a gyerekmoszat más gúnyolódásokat is képes létrehozni, így a gúnyolódó tárgyak örökösével végzed.
1. tanulási pont: amikor egy MagicMock objektumot függvényként hívunk, alapértelmezés szerint létrehoz egy új MagicMock objektumot.
vissza a példánkhoz. Eddig csak kigúnyolta simple_function, de nem tett semmit vele más, mint nyomtassa ki a MagicMocks, hogy jönnek létre ennek eredményeként. Tegyük fel, hogy meg akartam változtatni azt, amit a simple_function () – ból visszaküldtek, hogyan tenném ezt?, Ezt a magicmock return_value tulajdonságának használatával tenném (az első két nyomatot is eltávolítom, mivel már nincs rájuk szükség):
futtatáskor a kimenet:
You have mocked simple_function
amint láthatja, amikor a simple_function() most a MagicMock return_value-t visszaküldik, ahelyett, hogy létrehozna egy második MagicMock objektumot.
2. tanulási pont: ahhoz, hogy megváltoztassa azt, amit visszaad, amikor egy MagicMock objektumot függvénynek neveznek, állítsa be a return_value értéket.
Ha többet szeretne tenni, mint megváltoztatni a visszatérési értéket, akkor használhatja a MagicMock-ot.side_effect funkció., Ez lehetővé teszi egy teljesen új funkció megadását,amelyet a gúnyolódás helyett hívnak. Csináljuk. Először egy új függvényt definiálok, amely a side_effect lesz (megjegyzés, hogy ugyanazt a paramétert kell beállítania, mint a gúnyolódó funkció):
def side_effect_function():
return "SKABLAM!"
most meghatározhatunk egy új funkciót, amely ezt a mellékhatást így használja:
minden ugyanaz, mint a mock_simple_function, kivéve, ha a mock_simple_func side_effectjét állítom be a return_value helyett.,
a kimenet:
SKABLAM!
a mellékhatás használatának jó esete az, ha hibaáramot szeretne tesztelni, ezért kivételt szeretne emelni a teszt során. Megváltoztatom a side_effect_function-t, hogy hibát emeljek helyette:
def side_effect_function():
raise FloatingPointError("A disastrous floating point error has occurred")
most a kimenet (eltávolítottam a traceback egy részét az egyértelműség érdekében):
Traceback (most recent call last):
File "use_simple.py”, line 18, in side_effect_function
raise FloatingPointError("A disastrous floating point error has occurred”)
FloatingPointError: A disastrous floating point error has occurred
3.tanulási pont: többet tenni, mint egy MagicMock return_value-jának megváltoztatása, set side_effect.
gúnyos osztályok
eddig éppen kigúnyoltunk egy funkciót, de mit szólnál egy osztályhoz?, Nézzük meg egy osztály a simple.py az úgynevezett SimpleClass egy módszer az úgynevezett felrobban:
class SimpleClass(object):
def explode(self):
return "KABOOM!"
a use_simple.py írjunk egy függvényt, amely SimpleClass majd hívja ezt a funkciót:
def use_simple_class():
inst = simple.SimpleClass()
print(inst.explode())use_simple_class()
Ha a kimenet:
KABOOM!
Most adjuk meg a második funkciót, majd válassza ki, hogy kigúnyolja a teljes simple_class használja a @ál.patch decorator:
@mock.patch("simple.SimpleClass")
def mock_simple_class(mock_class):
mint amikor gúnyolódik egy függvény, a @mock.,patch decorator halad egy MagicMock tárgy, amely felváltja az osztály gúnyos be a funkció ez díszítő. Ebben az esetben a MagicMock objektum a mock_class argumentumhoz van rendelve.
pillanatnyilag csak kinyomtatom a MagicMock objektumot, majd futtatom a függvényt:
@mock.patch("simple.SimpleClass")
def mock_simple_class(mock_class):
print(mock_class)mock_simple_class()
a kimenet futtatásakor:
<MagicMock name='SimpleClass'>
mint egy függvény gúnyolódásakor, egy MagicMock objektum jön létre és kerül átadásra., Most lehetővé teszi, hogy nyomtassa ki SimpleClass így láthatja, hogy már kigúnyolták, és helyébe ugyanaz MagicMock objektum:
@mock.patch("simple.SimpleClass")
def mock_simple_class(mock_class):
print(mock_class)
print(simple.SimpleClass)
a kimenet most:
<MagicMock name='SimpleClass'>
<MagicMock name='SimpleClass'>
hozzunk létre egy példányt a SimpleClass azaz call SimpleClass (), majd nyomtassa ki. Emlékszel, mivel kigúnyolta SimpleClass, hogy valójában mi fog történni, hogy mi lesz, hívja a MagicMock tárgy, mint egy funkció:
A kimenet:
Tehát ahogy az várható volt, hívja SimpleClass (), ezért hívja a MagicMock tárgy, mint egy függvény létrehoz egy új MagicMock tárgy.,
eddig egy osztály gúnyolása olyan volt, mint egy függvény gúnyolása. A valóságban azonban, amikor egy osztályt definiálunk, akkor objektumokat hozunk létre az adott osztály használatával, és ezek az objektumok gyakrabban, mint nem, hogy valóban ki akarunk gúnyolni. A kérdés az, hogyan lehet gúnyolni egy osztályból létrehozott példányt? Nos, amikor egy osztályt gúnyolódsz, következésképpen egy MagicMock objektum jön létre, ha a return_value-ra utalsz azon a MagicMock objektumon, létrehoz egy új MagicMock objektumot, amely a létrehozott osztály példányát képviseli. Az istenit! Ez másfél mondat volt! Ez határozottan az egyik ” Aha!,”a pillanatok, de még a leírás sem teszi világossá. Nyomtassuk ki a return_value-t, hogy lássuk, mire gondolok:
a kimenet:
a harmadik sor a létrehozott osztály példányának nyomtatásából származik, a negyedik sor pedig a MagicMock objektum return_value nyomtatásából származik. Mint látható, hogy ugyanarra a MagicMock objektumra utalnak.
4. tanulási pont: amikor egy osztályt kigúnyol, egy MagicMock objektum jön létre. Az adott osztály egy példányának létrehozásakor egy új MagicMock objektum jön létre., Amikor az adott osztály MagicMock objektumának return_value-jára hivatkozik, ugyanazt a MagicMock objektumot kapja, amelyet az adott osztály példányának létrehozásakor hoztak létre.
” Ahhhhhh, miért fontos ez?!?!?”Hallom, hogy sírsz!
“fontos, ha ki akarja gúnyolni a felrobbanó funkciót”cserébe ordítok!
a következő kérdés, amelyet fel kell tennie: az a módszer, amelyet egy osztálymódszert vagy egy példánymódszert akarok gúnyolni? Mivel a módszer return_value változásának módja a választól függően eltérő lesz.,
Ha a módszer egy osztály módszer akkor állítsa be a return_value, mint így:
MagicMockObject.ClassMethodName.return_value = "A delightful return value"
De ha például egy módszer lenne:
MagicMockObject.return_value.InstanceMethodName.return_value = "A daring return value"
ezt szem előtt tartva változtassuk meg a return_value, az felrobbanhat, ami például módszer (majd távolítsa el a legtöbb nyomtatási nyilatkozatok az egyértelműség kedvéért) :
a fenti kód, mock_class.return_value visszaadja a Magicmock objektum, amely képviseli a példány SimpleClass.
mock_class.return_value.,explode visszaadja a Magicmock objektum, amely képviseli a felrobban eljárás például SimpleClass.
ezért állítsa be a mock_class return_value értékét.return_value.explode beállítja a Return_value a felrobban módszer a például SimpleClass.
a kimenet:
BOO!
ugyanúgy, mint egy függvény gúnyolódásakor, beállíthatja a side_effect-et osztályok és objektumok módszereire is.
remélem, ez a cikk segített megérteni a gúnyolódást egy kicsit. Kérjük, ajánlom, ha tetszett, és nyugodtan hagyja a választ, mint szeretném hallani tőled.