Python zesměšňovat tam je něco nejasné, o vás. Není snadné se s tím vyrovnat a trvá několik “ Ah, teď to chápu!“chvíli předtím, než budete lépe pochopeni., Jste výkonný, fantastický nástroj pro umožnění automatizovaných testů jednotek, ale vím, že mnoho vývojářů, kteří se „dostanou“ na znalosti, které mají, a psaní těchto testů trvá déle, než by mělo.
existuje mnoho článků o zesměšňování a ano, nyní píšu další. Nicméně, opravdu chci mít jít na to jasně vysvětlit, zejména ty “ Aha!“momenty, které posunuly mé porozumění dopředu.
Za prvé, co je výsměch? Zde je Citace z dokumentů:
mock je Knihovna pro testování v Pythonu., To vám umožní nahradit části testovaného systému falešnými objekty a učinit tvrzení o tom, jak byly použity.
takže „umožňuje nahradit části vašich systémů“, ale jaké části? Ukázalo se můžete vysmívat podstatě cokoliv, můžete definovat, jako:
- funkce
- přednášky
- předměty
nahradit s „mock objekty“, které jsou instancí Zesměšňovat nebo MagicMock třídy.,
poté „učiníte tvrzení“ o této falešné instanci, což je způsob, jak zkontrolovat, zda byla falešná instance použita tak, jak jste očekávali.
v tomto článku se budu zabývat základy výměny částí vašich systémů, ale nebudu pokrývat tvrzení.
začněme jednoduchým příkladem. Chystám se vytvořit nový modul s názvem simple.py a v tomto modulu budu definovat funkci nazvanou simple_function, že se jen vrací řetězec jako:
def simple_function():
return "You have called simple_function"
Teď jsem chtěl vytvořit druhý modul s názvem use_simple.py., V tomto modulu budu importovat mock balíček z unittest a importovat jednoduchý modul:
from unittest import mockimport simple
Příště budu psát dvě funkce, ten, který volá simple_function normálně a ten, který se vysmívá volání. Všimněte si, že normálně byste to udělali v testovacím kontextu, ale záměrně to odstraňuji, abych se mohl soustředit na zesměšňující část. První funkce:
def use_simple_function():
result = simple.simple_function()
print(result)use_simple_function()
jak vidíte, jen vytiskne výsledek simple_function., Konkrétně je výstup:
You have called simple_function
pro druhou funkci, abych zesměšnil simple_function budu používat mock.patch dekoratér. Tento dekoratér vám umožní určit, co chcete zesměšňovat tím, že předáte řetězec ve formátu ‚ balíček.modul.Název funkce“., V našem příkladu není žádný balíček, ale modul je volán jednoduchý a na funkce se nazývá simple_function, takže malíř bude vypadat takto:
@mock.patch('simple.simple_function')
potom Budeme muset napsat své druhé funkci jako tak:
@mock.patch('simple.simple_function')
def mock_simple_function():
já jsem to nazval mock_simple_function, ale to může být nazýván něco. Chybí nám zde parametr, protože když zdobíte funkci pomocí @ mock.patch projde instancí třídy MagicMock (objekt MagicMock), který se používá k nahrazení funkce, kterou zesměšňujete., Takže to bude vypadat takto:
@mock.patch('simple.simple_function')
def mock_simple_function(mock_simple_func):
takže zadáním @mock.náplast (‚jednoduché.simple_function‘) říkám, že chci nahradit simple_function objektem MagicMock přiřazeným parametru nazvanému mock_simple_func.
Nejprve pojďme maso z funkce tisk mock_simple_func a pak říkají:
Při spuštění, výstup je:
<MagicMock name='simple_function'>
Což je MagicMock objekt, který se bude jmenovat místo simple_function., Je důležité si uvědomit, že atribut názvu objektu je věc, která je zesměšňována, a id je jedinečné číslo pro objekt.
Když jsme nyní také vytisknout simple_function (ale ne volat to):
, Které produkuje výstup:
<MagicMock name='simple_function'>
<MagicMock name='simple_function'>
můžete vidět, že z odpovídající id, které mock_simple_func je stejný MagicMock objekt jako simple_function.
zatím tak dobrý. Vysmívali jsme se simple_function. Chcete-li být explicitní, simple_function byl zesměšňován, protože byl nahrazen magicmock objektem.,
Pojďme přidat řádky z první funkce:
Při spuštění, výstup je:
Jak můžete vidět z třetí linie výstupu, když simple_function je vlastně volal to vytváří různé MagicMock objektu. Nezapomeňte, že protože jsme se posmívali simple_function, je to vlastně objekt MagicMock,takže když voláme simple_function, ve skutečnosti voláme objekt MagicMock!
pro mě, to je místo, kde zmatek zapadá.
- proč je vytvořen nový objekt MagicMock?
- a jak na zemi můžete volat objekt stejně?, Normálně dostanete „TypeError: ‚****‘ objekt není možné volat“, když se pokusíte.
zastavme se na minutu, abychom se podrobněji podívali na MagicMock.
MagicMock má magii ve svém názvu, protože má výchozí implementace většiny magických metod Pythonu. Co je to Python magická metoda ptáte? To vše jsou speciální python funkce, které mají dvojí podtržítko na začátku a na konci svého jména. Jejich seznam najdete zde. Ten, který je zde zajímavý, je _ _ call__., Volání funkce je popsána jako:
volána, když objekt je nazýván jako funkce
Takže pokud třída implementuje tuto funkci můžete vytvořit instanci třídy, a pak zavolat, že instance jako funkce, tj. :
Proto, když MagicMock se nazývá jako funkce, v __call__ funkce je volána. Implementace této funkce MagicMock vytváří nový maket!
takže když voláme simple_function (), vytvoří se a vrátí se nový maket. Nejen to, ale máme koncept rodičů a dětských výsměchů., Když jeden falešný vytvoří další, stane se rodičem a nově vytvořeným dítětem. Ten dětský posměch by mohl vytvořit další posměšky, takže skončíte s dědictvím falešných objektů.
Learning point 1: když se objekt MagicMock nazývá jako funkce, ve výchozím nastavení vytvoří a vrátí nový objekt MagicMock.
zpět na náš příklad. Zatím jsme se jen posmívali simple_function ale neudělal nic jiného, než vytisknout MagicMocks, které jsou vytvořeny jako výsledek. Řekněme, že jsem chtěl změnit to, co bylo vráceno z simple_function (), jak bych to udělal?, Udělal bych to pomocí return_value majetku MagicMock jako tak (já jsem také bude odstranit první dva otisky tak, jak jsou již není potřeba):
Při spuštění, výstup je:
You have mocked simple_function
Jak můžete vidět, když simple_function() se nyní nazývá MagicMock return_value je vrácena namísto vytváření druhé MagicMock objektu.
Learning point 2: Chcete-li změnit to, co se vrací, když se objekt MagicMock nazývá jako funkce, Nastavte return_value.
Pokud chcete udělat více než změnit návratovou hodnotu, můžete použít MagicMock.funkce side_effect., To vám umožní určit zcela novou funkci, která bude volána namísto té, kterou zesměšňujete. Pojďme na to. Za prvé, budu definovat novou funkci, která bude side_effect (všimněte si, že musí mít stejný parametr nastavit jako funkce, kterou posměšně):
def side_effect_function():
return "SKABLAM!"
Nyní můžeme definovat novou funkci, která používá tento nežádoucí účinek jako tak:
Všechno je stejné jako mock_simple_function dále jen jsem nastavení side_effect z mock_simple_func místo return_value.,
výstup:
SKABLAM!
dobrý případ použití pomocí vedlejší efekt je, pokud si chcete vyzkoušet chyba průtoku, a proto chcete vyvolat výjimku v testu. Budu měnit side_effect_function zvýšit chybová místo:
def side_effect_function():
raise FloatingPointError("A disastrous floating point error has occurred")
výstup je (odstranil jsem část traceback pro přehlednost):
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
Učení bod 3: udělat víc, než jen změnit return_value z MagicMock, nastavit side_effect.
zesměšňující třídy
zatím jsme jen zesměšnili funkci, ale co třída?, Dejte nám definovat třídu v simple.py volal SimpleClass s metodou tzv. explodovat:
class SimpleClass(object):
def explode(self):
return "KABOOM!"
v use_simple.py pojďme napsat funkci, která používá SimpleClass a pak volání funkce:
def use_simple_class():
inst = simple.SimpleClass()
print(inst.explode())use_simple_class()
Při spuštění výstup je:
KABOOM!
Teď pojďme definovat druhou funkci a vybrat zesměšňovat rozsahu simple_class pomocí @mock.patch decorator:
@mock.patch("simple.SimpleClass")
def mock_simple_class(mock_class):
jako při zesměšňování funkce, @mock.,patch dekoratér prochází magicmock objekt, který nahrazuje třídu, kterou se vysmívá do funkce, kterou zdobí. Objekt MagicMock je v tomto případě přiřazen argumentu mock_class.
Pro tuto chvíli jsem se jen vytisknout MagicMock objekt a potom spusťte funkci:
@mock.patch("simple.SimpleClass")
def mock_simple_class(mock_class):
print(mock_class)mock_simple_class()
Při spuštění výstup je:
<MagicMock name='SimpleClass'>
stejně Jako s posměšným funkce a MagicMock objekt je vytvořen a předán., Nyní umožňuje vytisknout SimpleClass takže můžete vidět, že byl terčem posměchu a nahrazuje se stejným MagicMock objekt:
@mock.patch("simple.SimpleClass")
def mock_simple_class(mock_class):
print(mock_class)
print(simple.SimpleClass)
výstup je:
<MagicMock name='SimpleClass'>
<MagicMock name='SimpleClass'>
Pojďme vytvořit instanci SimpleClass tj. volání SimpleClass(), a pak je vytisknout. Pamatujte si, že od doby, co jsme vysmíval SimpleClass, co se vlastně bude dít, je že budeme volat MagicMock objekt jako funkci.
výstup:
Tak, jak se očekávalo, volání SimpleClass (), a proto volá MagicMock objekt jako funkce vytvoří nový MagicMock objektu.,
až dosud bylo zesměšňování třídy podobně jako zesměšňování funkce. Ve skutečnosti však, když definujeme třídu, vytvoříme objekty pomocí této třídy a tyto objekty jsou častěji než ne, že se opravdu chceme zesměšňovat. Otázkou je, jak zesměšnit instanci vytvořenou ze třídy? No, když se vysmíváte třídě a následně je vytvořen objekt MagicMock, pokud odkazujete na return_value na tento objekt MagicMock, vytvoří nový objekt MagicMock, který představuje instanci vytvořené třídy. Blimey! To byla věta a půl! To byl určitě jeden z mých “ Aha!,“momenty, ale ani psaní to nedává jasně najevo. Pojďme vytisknout return_value, takže můžete vidět, co mám na mysli:
výstup:
třetí řádek je z tisku instanci třídy vytvořen, a čtvrtý řádek je z tisku return_value z MagicMock objekt předán do funkce. Jak vidíte, odkazují na stejný objekt MagicMock.
bod učení 4: když zesměšňujete třídu, vytvoří se objekt MagicMock. Když vytvoříte instanci této třídy, vytvoří se nový objekt MagicMock., Když odkazujete na return_value objektu MagicMock této třídy, získáte stejný objekt MagicMock, který byl vytvořen, když byla vytvořena instance této třídy.
“ Ahhhhh, proč je to důležité?!?!?“Slyším tě plakat!
„je důležité, pokud chcete zesměšnit funkci explode“ i bellow na oplátku!
Další otázka, kterou musíte položit, je: je metoda, kterou chci zesměšnit třídní metodu nebo metodu instance? Protože jak změníte return_value metody se bude lišit v závislosti na odpovědi.,
v Případě, že metoda byla metoda třídy, pak byste nastavit return_value tak jako:
MagicMockObject.ClassMethodName.return_value = "A delightful return value"
Ale když šlo o metodu instance byste to udělat:
MagicMockObject.return_value.InstanceMethodName.return_value = "A daring return value"
S tímto na mysli pojďme změnit return_value z explodovat, což je metoda instance (budu odstranit většinu tisku výkazů pro přehlednost) :
V kódu výše, mock_class.return_value vrací objekt MagicMock, který představuje instanci SimpleClass.
mock_class.return_value.,explode vrací objekt MagicMock, který představuje metodu explode instance SimpleClass.
proto nastavte return_value of mock_class.return_value.explode nastaví return_value metody explode instance SimpleClass.
výstup:
BOO!
podobně, jako když se vysmívá funkce, můžete nastavit side_effect pro metody třídy a objekty.
doufám, že tento článek vám pomohl pochopit zesměšňování trochu víc. Prosím, doporučujeme, pokud se vám to líbilo a neváhejte zanechat odpověď, jak bych rád slyšel od vás.