Úvod do Zesměšňovat v Pythonu

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 oproti zažívá vaše CD zásobník otevřít pokaždé, když je spuštěn test.,

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:

  1. zesměšnit metodu RemovalService.rm.,
  2. 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.,

Share

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *