Jak Spustit Unit Testy v Pythonu Bez Testování Vaši Trpělivost
Více často než ne, software, který napíšeme přímo interaguje s tím, co bychom označit jako „špinavé“ služby. Laicky řečeno: služby, které jsou pro naši aplikaci klíčové, ale jejichž interakce mají zamýšlené, ale nežádoucí vedlejší účinky-tedy nežádoucí v kontextu autonomního zkušebního běhu.,facebook facebook: například: možná píšeme sociální aplikaci a chceme vyzkoušet naši novou funkci „Post to Facebook“, ale nechceme skutečně posílat na Facebook pokaždé, když spustíme naši testovací sadu.
Python unittest
knihovna obsahuje subpackage jménem unittest.mock
—nebo pokud jste deklarovat to jako závislost, prostě mock
—která nabízí velmi silný a užitečný prostředek, který mock a stub tyto nežádoucí vedlejší účinky.,
Poznámka: mock
je nově součástí standardní knihovny Pythonu 3.3; před distribucí, budete muset použít Mock knihovna ke stažení přes PyPI.
Volání Systému vs. Python Zesměšňovat
dám vám další příklad, a ten, který budeme spouštět s pro zbytek článku, zvažte systémových volání., To není těžké vidět, že tito jsou hlavními kandidáty pro výsměch: to, zda jste psaní skriptu pro vysunutí CD disku, webového serveru, který odstraní zastaralé soubory v mezipaměti /tmp
, nebo socket server, který se váže na TCP port, tyto hovory všechny mají nežádoucí vedlejší účinky v souvislosti s vaší unit-testy.
Jako vývojář, budete pečovat více, že vaše knihovna úspěšně názvem funkce systému pro vysunutí CD (s správné argumenty, atd.) na rozdíl od skutečnosti zažívá vaše CD zásobník otevřít pokaždé, když test je spuštěn. (Nebo horší, vícekrát, protože více testů odkazuje na kód vysunutí během jediného zkušebního běhu jednotky!)
Také, aby vaše unit-testy, efektivní a výkonný znamená jak držet hodně „pomalý kód“ z automatizované zkušební jízdy, a to souborový systém a přístup k síti.,
pro náš první příklad přeformátujeme standardní testovací případ Pythonu z původního formuláře na jeden pomocí mock
. Budeme demonstrovat, jak napsat testovací případ s vysmívá se, aby naše testy chytřejší, rychlejší, a je schopen odhalit více o tom, jak software funguje.
Jednoduchá funkce mazání
všichni musíme čas od času odstranit soubory z našeho souborového systému, takže napíšeme funkci v Pythonu, která nám usnadní skripty.,
#!/usr/bin/env python# -*- coding: utf-8 -*-import osdef rm(filename): os.remove(filename)
je Zřejmé, že naše rm
metoda v tuto chvíli nebude poskytovat mnohem více než základní os.remove
metoda, ale naše codebase zlepší, což nám umožňuje přidat další funkce.
Pojďme napsat tradiční testovací případ, tj., bez vysmívá:
Naše testovací případ je velmi jednoduchý, ale pokaždé, když je spuštěn, je vytvořen dočasný soubor a potom odstraněn., Navíc nemáme žádný způsob testování, zda naše metoda rm
správně předá argument naos.remove
volání. Můžeme předpokládat, že to dělá na základě výše uvedeného testu, ale mnoho je ponecháno na přání.
Refaktoring s Python Vysmívá
řekněme, refaktorovat naše testovací případ pomocí mock
:
S těmito refactors, máme zásadně změnil způsob, jakým, že test funguje. Nyní máme insider, objekt, který můžeme použít k ověření funkčnosti jiného.,
Potenciální Python Zesměšňovat Úskalí
Jedna z prvních věcí, které se měli držet je, že jsme pomocí mock.patch
metoda natěrač mock objekt se nachází na mymodule.os
, a vstřikování, které zesměšňují v našem testovacím případě metody. Nemělo by větší smysl jen zesměšňovat os
než odkaz na něj na mymodule.os
?
Pokud jde o import a správu modulů, Python je poněkud záludný had., Za běhu má modul mymodule
vlastní os
, který je v modulu importován do vlastního lokálního rozsahu. Pokud tedy zesměšníme os
, neuvidíme účinky makety v modulu mymodule
.
mantru opakovat, je toto:
Mock položku, kde se používá, ne odkud to je.,
Pokud potřebujete, aby zesměšňovat tempfile
modul myproject.app.MyElaborateClass
, pravděpodobně budete muset použít mock myproject.app.tempfile
, protože každý modul udržuje vlastní dovoz.
s tímto úskalím z cesty, pokračujme v posměchu.
přidání validace do’rm‘
metoda rm
definovaná dříve je poměrně Zjednodušená. Chtěli bychom, aby to ověřilo, že cesta existuje a je soubor, než se slepě pokusí odstranit., Pojďme refactor rm
být trochu chytřejší:
#!/usr/bin/env python# -*- coding: utf-8 -*-import osimport os.pathdef rm(filename): if os.path.isfile(filename): os.remove(filename)
skvělé. Nyní upravme náš testovací případ, abychom udrželi pokrytí.
naše testovací paradigma se zcela změnila. Nyní můžeme ověřit a ověřit vnitřní funkčnost metod bez jakýchkoli vedlejších účinků.
Soubor-Odstranění jako Služba s Předstíranou Patch
zatím jsme pracovali jen s dodávající zesměšňuje pro funkce, ale ne pro metody na objektech nebo v případech, kde zesměšňovat je nutné pro odeslání parametry. Nejprve pokryjeme objektové metody.,
začneme refaktorem metody rm
do třídy služeb. Opravdu neexistuje ospravedlnitelná potřeba zapouzdřit tak jednoduchou funkci do objektu,ale přinejmenším nám to pomůže prokázat klíčové pojmy v mock
. Pojďme refactor:
všimnete si, že se v našem testovacím případě příliš nezměnilo:
skvělé, takže nyní víme, že RemovalService
funguje podle plánu., Pojďme vytvořit další službu, která deklaruje to jako závislost:
Jelikož už máme test pokrytí na RemovalService
, nebudeme k ověření vnitřní funkce rm
metoda v našich testech UploadService
. Spíše budeme jednoduše testovat (samozřejmě bez vedlejších účinků), že UploadService
volá metodu RemovalService.rm
, kterou známe „just works™“ z našeho předchozího testovacího případu.
existují dva způsoby, jak toho dosáhnout:
- zesměšnit metodu
RemovalService.rm
., - uveďte zesměšněnou instanci v konstruktoru
UploadService
.
protože obě metody jsou často důležité při testování jednotek, přezkoumáme oba.
1. Možnost: Zesměšňovat Metody Instance
mock
knihovna má zvláštní způsob natěrač pro zesměšňovat objekt, instance, metody a vlastnosti, @mock.patch.object
malíř
Skvěle! Ověřili jsme, že UploadService
úspěšně volá metodu rm
. Všiml sis tam něčeho zajímavého?, Patchování mechanismus vlastně nahradil rm
metoda RemovalService
instance v naší zkušební metody. To znamená, že můžeme skutečně zkontrolovat samotné instance. Pokud chcete vidět více, zkuste vrácení v zarážku ve vašem zesměšňovat kód získat dobrý pocit, pro jak záplatování mechanismus funguje.
Mock Patch Pitfall: Decorator Order
při použití více dekoratérů na vašich testovacích metodách je objednávka důležitá a je to trochu matoucí. V zásadě při mapování dekoratérů na parametry metody pracujte dozadu., Zvažte tento příklad:
Všimněte si, jak jsou naše parametry přizpůsobeny opačnému pořadí dekoratérů? To je částečně kvůli způsobu, jakým Python funguje. S více metoda dekoratéry, zde je pořadí provádění v pseudokódu:
patch_sys(patch_os(patch_os_path(test_something)))
Od patch sys
je nejvzdálenější patch, bude popraven poslední, což je poslední parametr v aktuální zkušební metoda argumenty. Vezměte na vědomí tuto studnu a při provádění testů použijte ladicí program, abyste se ujistili, že správné parametry jsou injikovány ve správném pořadí.,
2. Možnost: Vytváření Mock Instance
Místo toho, zesměšňovat konkrétní metodu instance, mohli jsme místo toho jen dodat zesměšňoval například na UploadService
s jeho konstruktor. Preferuji možnost 1 výše, protože je to mnohem přesnější, ale existuje mnoho případů, kdy by možnost 2 mohla být účinná nebo nezbytná. Pojďme refaktorovat náš test znovu:
V tomto příkladu, ani jsme neměli na opravu žádné funkce, jsme jednoduše vytvořit auto-spec pro RemovalService
třídy, a pak aplikovat tomto případě do UploadService
ověřit funkčnost.,
metodamock.create_autospec
vytváří funkčně ekvivalentní instanci k dané třídě. Co to znamená, prakticky řečeno, je to, že když je vrácená instance interagována, zvýší výjimky, pokud budou použity nezákonným způsobem. Konkrétněji, pokud je metoda volána se špatným počtem argumentů, bude zvýšena výjimka. To je nesmírně důležité, protože refaktory se stávají. Jak se Knihovna mění, testy se rozbijí a to se očekává. Bez použití auto-spec budou naše testy stále procházet, i když je základní implementace přerušena.,
Úskalí: mock.Mock
mock.MagicMock
Třídy
mock
knihovna také obsahuje dvě důležité třídy, na které většina z vnitřní funkčnost je postavena na: mock.Mock
mock.MagicMock
. Když možnost je použít mock.Mock
, např. mock.MagicMock
instance, nebo auto-spec, vždy prospěch pomocí auto-spec, protože to pomáhá udržet vaše testy normální pro budoucí změny., Je to proto, že mock.Mock
mock.MagicMock
přijmout všechna volání metody a majetek úkoly bez ohledu na základní API. Zvažte následující případ užití:
class Target(object): def apply(value): return valuedef method(target, value): return target.apply(value)
test mock.Mock
například takto:
Tato logika se zdá rozumný, ale pojďme to změnit na Target.apply
způsob, aby se více parametrů:
class Target(object): def apply(value, are_you_sure): if are_you_sure: return value else: return None
Re-spustit test a zjistíte, že to stále prochází. To proto, že není postaven proti vaší skutečné API., To je důvod, proč byste měli vždy použít create_autospec
metoda autospec
parametr @patch
@patch.object
dekoratérů.
Python Mock Příklad: Zesměšňovat Facebook API Volání
dokončit, pojďme napsat další použitelné v reálném světě python mock příklad, který jsme zmínili v úvodu: odeslání zprávy na Facebook. Napíšeme pěknou třídu obalů a odpovídající testovací případ.,
Tady je náš test, který zkontroluje, že jsme se po poselství, aniž by ve skutečnosti odeslání zprávy:
Jak jsme viděli dosud, je to opravdu jednoduché začít psát chytřejší testy s mock
v Pythonu.
Závěr
Python mock
knihovna, i když trochu matoucí pro práci s, je hra-changer pro unit-testování. Dokázali jsme, běžné případy použití pro začínáme pomocí mock
unit-testování, a doufejme, že tento článek pomůže Python vývojáře překonat počáteční překážky a psát vynikající, testovaný kód.,