Použití Pythonu pro tvorbu testů: použití třídy Mock z knihovny unittest.mock

7. 5. 2020
Doba čtení: 36 minut

Sdílet

 Autor: Depositphotos
Ve druhé části seriálu o testování s Pythonem si popíšeme další možnosti, které jsou nabízeny knihovnou unittest.mock. Ukážeme použití třídy nazvané Mock, zjistíme, zda jsou mockované funkce volány s očekávanými parametry.

Obsah

1. Použití Pythonu pro tvorbu testů: použití třídy Mock z knihovny unittest.mock

2. Zjištění, zda byla mockovaná funkce zavolána

3. Problematika mockování funkce, která je volaná nepřímo

4. Mockování funkce volané nepřímo

5. Modifikace kódu v případě, že použijeme import a nikoli from X import

6. Mockování metod

7. Testovaná třída

8. Nepřímé volání metody, kterou budeme mockovat

9. Mockování nepřímo volané metody

10. Složitější aplikace implementovaná ve větším množství modulů

11. Mockování funkcí volaných nepřímo z jiných modulů

12. Výsledek spuštění testů

13. Mockování funkce přímo volané z testů

14. Výsledek spuštění testů

15. Přímé použití konstruktoru patch() v těle testů

16. Další možnosti nabízené objekty Mock a MagicMock

17. Zjištění kolikrát a s jakými parametry byla mockovaná funkce zavolána

18. Repositář s demonstračními příklady

19. Předchozí články s tématem testování (nejenom) v Pythonu

20. Odkazy na Internetu

1. Použití Pythonu pro tvorbu testů: použití třídy Mock z knihovny unittest.mock

Ve druhé části seriálu o testování s využitím programovacího jazyka Python si popíšeme některé další užitečné možnosti, které jsou programátorům nabízeny knihovnou unittest.mock. Zejména si ukážeme způsoby použití tříd nazvaných Mock a MagicMock (což je třída odvozená od třídy Mock), seznámíme se s možnostmi zjištění (otestování), zda jsou mockované funkce volány s očekávanými parametry a samozřejmě nezapomeneme ani na velmi důležitou „maličkost“ – jakým způsobem se mockování použije společně se standardním testovacím frameworkem pytest (protože právě při skutečném testování se mockování funkcí a metod provádí nejčastěji, i když oblasti použití jsou ve skutečnosti větší).

Připomeňme si, že v současnosti existuje relativně velké množství různých knihoven, které mockování funkcí a metod v Pythonu umožňují (není se ostatně čemu divit, protože samotná podstata jazyka Python tyto operace umožňuje implementovat relativně snadno). Z těchto knihoven jsme již minule jmenovali projekt Flexmock, který naleznete na adrese https://pypi.python.org/py­pi/flexmock. V Pythonu 3.x se standardem v této oblasti stala knihovna nazvaná unittest.mock. V případě, že ještě z nějakého důvodu musíte používat Python 2.x, použijte namísto knihovny unittest.mock knihovnu nazvanou jednoduše mock. Tato knihovna nabízí prakticky stejné možnosti jako unittest.mock (je ostatně založena na stejném základním kódu, který pouze byl pro potřeby Pythonu 2.x upraven), ovšem lze ji použít jak v Pythonu 2.x, tak i v Pythonu 3.x, a to bez toho, abyste museli upravovat zdrojové kódy vašich testů (samozřejmě za předpokladu, že se v nich nevyskytují konstrukce, které nejsou v Pythonu 2.x podporovány).

Poznámka: (již naposledy k Pythonu 2 v tomto seriálu) všechny dále popsané demonstrační příklady byly odzkoušeny společně s Pythonem 3.x (od verze 3.4 včetně). Úprava příkladů pro Python 2.x by však měla být velmi snadná.

2. Zjištění, zda byla mockovaná funkce zavolána

Mnohdy, zejména při testování složitěji strukturovaného programového kódu s mnoha podmínkami, popř. rozsáhlejším stavovým prostorem aplikace, je důležité zjistit, zda se vůbec mockovaná funkce při spuštění jednotkových testů zavolala. A právě v těchto případech nám přijde vhod objekt, který je do testovací funkce automaticky předáván, v našem případě v prvním parametru (jméno tohoto parametru si můžeme vybrat sami, důležité je pouze znát jeho pořadí/index):

@patch('application.function1', side_effect=side_effect_handler)
def test3(mocked_function_object):
    ...
    ...
    ...

Tento objekt obsahuje mj. i vlastnost (property) pojmenovanou jednoduše called. Ve výchozím stavu je tato vlastnost nastavena na hodnotu False, ale po prvním zavolání mockované funkce se vlastnost nastaví na hodnotu True. Ostatně se o tomto chování můžeme rychle přesvědčit, a to velmi snadno – vypíšeme hodnotu vlastnosti called před vlastním voláním mockované funkce a taktéž ihned po tomto volání. Upravený jednotkový test bude vypadat následovně:

def side_effect_handler():
    print("side_effect function called")
    return -1
 
 
@patch('application.function1', side_effect=side_effect_handler)
def test3(mocked_function_object):
    print("mocked function called: {c}".format(c=mocked_function_object.called))
    print(application.function1())
    print("mocked function called: {c}".format(c=mocked_function_object.called))

Po zavolání testovací funkce test3 by se na standardní výstup měla vypsat následující sekvence zpráv:

mocked function called: False
side_effect function called
-1
mocked function called: True

Podobně tomu bude v případě, že kombinujeme vlastní handler se specifikací návratové hodnoty (handler je tedy zavolán, jeho volání je korektně zaregistrováno, ovšem nakonec se použije programátorem specifikovaná návratová hodnota):

def side_effect_handler_2():
    print("side_effect function called")
    return DEFAULT
 
 
@patch('application.function1', return_value=42, side_effect=side_effect_handler_2)
def test5(mocked_function):
    print("mocked function called: {c}".format(c=mocked_function.called))
    print(application.function1())
    print("mocked function called: {c}".format(c=mocked_function.called))

Výsledky po spuštění:

mocked function called: False
side_effect function called
42
mocked function called: True

Pro úplnost si v této kapitole opět ukážeme úplný zdrojový kód výše popsaného demonstračního příkladu. V případě potřeby ho naleznete na adrese https://github.com/tisnik/testing-in-python/tree/master/unittest_mock/mock-test3:

Soubor application.py s testovanou funkcí

"""Implementace logiky aplikace, kterou budeme testovat."""
 
 
def function1():
    """Funkce, kterou v testech nahradíme mockem."""
    print("function1 called")
    return "tested function"

Soubor test.py

"""Implementace jednotkových testů."""
 
from unittest.mock import *
 
import application
 
 
def test1():
    """První test neprovádí prakticky žádné reálné kontroly, jen zavolá testovanou funkci."""
    print(application.function1())
 
 
@patch('application.function1', return_value=42)
def test2(mocked_function):
    """Druhý test používá fake test double - náhradu volané funkce."""
    print(application.function1())
 
 
def side_effect_handler():
    """Implementace handleru - stub funkce nahrazované mockem."""
    print("side_effect function called")
    return -1
 
 
@patch('application.function1', side_effect=side_effect_handler)
def test3(mocked_function):
    """Třetí test používá stub test double - náhradu volané funkce."""
    # vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function.called))
    print(application.function1())
    # opět vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function.called))
 
 
@patch('application.function1', return_value=42, side_effect=side_effect_handler)
def test4(mocked_function):
    """Čtvrtý test se snaží zkombinovat fake a stub."""
    print(application.function1())
 
 
def side_effect_handler_2():
    """Implementace handleru - stub funkce nahrazované mockem, který ovšem ovlivňuje chování testu."""
    print("side_effect function called")
    return DEFAULT
 
 
@patch('application.function1', return_value=42, side_effect=side_effect_handler_2)
def test5(mocked_function):
    """Pátý test se opět snaží zkombinovat fake a stub."""
    # vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function.called))
    print(application.function1())
    # opět vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function.called))
 
 
if __name__ == '__main__':
    print("*** test1 ***")
    test1()
    print()
 
    print("*** test2 ***")
    test2()
    print()
 
    print("*** test3 ***")
    test3()
    print()
 
    print("*** test4 ***")
    test4()
    print()
 
    print("*** test5 ***")
    test5()
    print()

3. Problematika mockování funkce, která je volaná nepřímo

Nyní se dostáváme k velmi důležité vlastnosti knihovny unittest.mock, kterou je užitečné správně pochopit (už jen z toho důvodu, že dokumentace tuto vlastnost podle mého názoru nepopisuje do všech podrobností, o čemž ostatně svědčí poměrně časté dotazy na fórech). Týká se to způsobu určení plného jména funkce, která má být nahrazena svojí „falešnou“ variantou, tedy mockem. Nejdříve si naschvál zkomplikujeme kód naší aplikace, kterou budeme testovat. V upravené variantě budou aplikaci tvořit dvě funkce nazvané function1 a function2, přičemž si povšimněte, že se z funkce function1 volá funkce function2 (konkrétně v rámci příkazu return, ale to v tomto konkrétním případě není tak důležité – podstatný je fakt, že k volání dojde):

"""Implementace logiky aplikace, kterou budeme testovat."""
 
 
def function1():
    """První funkce, která volá funkci druhou."""
    print("function1 called")
    return function2()
 
 
def function2():
    """Druhá funkce, kterou v testech nahradíme mockem."""
    print("function2 called")
    return "function 2"

4. Mockování funkce volané nepřímo

Komplikace nastanou ve chvíli, kdy budeme potřebovat nahradit funkci function2 za její falešnou variantu, tedy za mock. Tuto funkci totiž nebudeme volat přímo z testu, ale pouze nepřímo – přes vlastní kód aplikace. A právě v tomto okamžiku se projevuje již výše zmíněná vlastnost – do anotace @patch je nutné uvést jméno funkce tak, jak ji vidí volající kód. Co to pro nás znamená? Funkce function2 je volána z funkce pojmenované function1 a přitom k tomuto volání dochází v modulu application. Plné jméno mockované funkce tedy bude v tomto konkrétním případě znít application.function2, což jen náhodou odpovídá stejnému jménu, jakoby se funkce volala přímo z testů (lze totiž zavolat i funkci z jiného balíčku atd.). Podívejme se nyní na příklady jednotkových testů.

Nejprve změníme import testovaného modulu takovým způsobem, aby nebylo nutné při volání funkcí z modulu application používat celé jméno tohoto modulu s tečkou:

from unittest.mock import *
 
from application import *

Můžeme si otestovat, že se funkce z modulu application mohou volat přímo (jsou totiž naimportovány do aktuálního jmenného prostoru):

def test1():
    print("function1 returns: {v}".format(v=function1()))

Výsledek je prozatím uspokojující:

function1 called
function2 called
function1 returns: function 2

Správné určení funkce, která se má mockovat, bude vypadat následovně – funkce je totiž volána nepřímo v modulu application a nikoli v modulu test (který je aktuálně nastaven), což se musí projevit v dekorátoru:

@patch('application.function2', return_value=42)
def test2(mocked_function_object):
    print("mocked function called: {c}".format(c=mocked_function_object.called))
    print("function1 returns: {v}".format(v=function1()))
    print("mocked function called: {c}".format(c=mocked_function_object.called))

Výsledek bude v tomto případě vypadat takto:

mocked function called: False
function1 called
function1 returns: 42  < zde se volá mock namísto "pravé" funkce function2
mocked function called: True

Jakmile známe správné jméno funkce, můžeme samozřejmě použít i její falešnou verzi, například následovně:

def side_effect_handler():
    print("side_effect_handler function called")
    return -1
 
 
@patch('application.function2', side_effect=side_effect_handler)
def test3(mocked_function_object):
    print("mocked function called: {c}".format(c=mocked_function_object.called))
    print(function1())
    print("mocked function called: {c}".format(c=mocked_function_object.called))

Výsledek:

mocked function called: False
function1 called
side_effect_handler function called
-1
mocked function called: True

Podobně, jako tomu bylo ve druhé kapitole, si uvedeme úplný zdrojový kód dnešního v pořadí druhého demonstračního příkladu, jenž je opět složen ze dvou souborů – application.py a test.py (a z pomocného souboru main.py). Tento příklad naleznete na adrese https://github.com/tisnik/testing-in-python/tree/master/unittest_mock/mock-test4:

Soubor application.py s testovanou funkcí

"""Implementace logiky aplikace, kterou budeme testovat."""
 
 
def function1():
    """První funkce, která volá funkci druhou."""
    print("function1 called")
    return function2()
 
 
def function2():
    """Druhá funkce, kterou v testech nahradíme mockem."""
    print("function2 called")
    return "function 2"

Soubor test.py

"""Implementace jednotkových testů."""
 
from unittest.mock import *
 
from application import *
 
 
def test1():
    """První test neprovádí prakticky žádné reálné kontroly, jen zavolá testovanou funkci."""
    print("function1 returns: {v}".format(v=function1()))
 
 
@patch('application.function2', return_value=42)
def test2(mocked_function):
    # vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function.called))
    print("function1 returns: {v}".format(v=function1()))
    # opět vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function.called))
 
 
def side_effect_handler():
    print("side_effect_handler function called")
    return -1
 
 
@patch('application.function2', side_effect=side_effect_handler)
def test3(mocked_function):
    # vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function.called))
    print(function1())
    # opět vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function.called))
 
 
if __name__ == '__main__':
    test1()
    print()
 
    test2()
    print()
 
    test3()
    print()

5. Modifikace kódu v případě, že použijeme import a nikoli from X import

Dnešní třetí demonstrační příklad je založen na prakticky stejném kódu jako příklad předchozí, ovšem s tím podstatným rozdílem, že se modul application importuje do testů nikoli příkazem:

from application import *

ale naopak následujícím způsobem:

import application

To vede k tomu, že přímé volání funkcí z modulu application je nutné provádět s uvedením jména modulu. Samotné testy a dokonce ani obsah dekorátoru (v jiných programovacích jazycích anotace) @patch se ovšem žádným způsobem nezmění. Testy nyní budou vypadat následovně:

from unittest.mock import *
 
import application
 
 
def test1():
    """První test neprovádí prakticky žádné reálné kontroly, jen zavolá testovanou funkci."""
    print("function1 returns: {v}".format(v=application.function1()))
 
 
@patch('application.function2', return_value=42)
def test2(mocked_function_object):
    # vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function_object.called))
    print("function1 returns: {v}".format(v=application.function1()))
    # opět vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function_object.called))
 
 
def side_effect_handler():
    print("side_effect_handler function called")
    return -1
 
 
@patch('application.function2', side_effect=side_effect_handler)
def test3(mocked_function_object):
    # vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function_object.called))
    print("function1 returns: {v}".format(v=application.function1()))
    # opět vytiskneme informaci o tom, zda se mockovaná funkce zavolala
    print("mocked function called: {c}".format(c=mocked_function_object.called))
 
 
if __name__ == '__main__':
    test1()
    print()
 
    test2()
    print()
 
    test3()
    print()

Výsledek běhu testů již dokážeme velmi dobře předvídat:

function1 called
function2 called
function1 returns: function 2
 
mocked function called: False
function1 called
function1 returns: 42
mocked function called: True
 
mocked function called: False
function1 called
side_effect_handler function called
function1 returns: -1
mocked function called: True
Poznámka: tento demonstrační příklad je umístěn na adrese https://github.com/tisnik/testing-in-python/tree/master/unittest_mock/mock-test5.

6. Mockování metod

Prakticky stejným způsobem, jakým jsme vytvářeli „falešné“ varianty běžných funkcí (tedy mocky), je možné nahrazovat metody vybraných tříd. Ostatně v programovacím jazyku Python není mezi funkcemi a metodami tak velký rozdíl, jako v některých jiných programovacích jazycích, které před programátory skrývají (mj) implicitní parametr self či this. V následujících třech kapitolách si ukážeme vytvoření jednoduchého mocku nepřímo volané (nestatické a netřídní) metody.

7. Testovaná třída

Třída, kterou budeme testovat, je opět velmi jednoduchá. Kromě konstruktoru obsahuje i dvě metody nazvané method1 a method2, přičemž druhá metoda je automaticky volána z metody první (opět v příkazu return, což ovšem není podstatné):

"""Implementace logiky aplikace, kterou budeme testovat."""
 
 
class Application:
    def __init__(self):
        pass
 
    def method1(self):
        """První metoda, která volá metodu druhou."""
        print("method1 called")
        return self.method2()
 
    def method2(self):
        """Druhá metoda, kterou v testech nahradíme mockem."""
        print("method2 called")
        return "method 2"

Poznámka: ve skutečnosti obě metody nepřistupují k žádnému atributu objektu, takže by se z nich mohly stát statické metody pomocí anotace @staticmethod; alternativně i třídní metody. Nicméně pro jednoduchost zatím uvažujme o nestatických metodách, kterým se při jejich volání explicitně předává i parametr self.

8. Nepřímé volání metody, kterou budeme mockovat

Samotný modul s testem bude začínat přesně tak, jak jsme zvyklí, tj. importem třídy unittest.mock i třídy Application uložené v modulu application:

from unittest.mock import *
 
from application import Application

První jednotkový test prozatím žádnou mockovanou funkci nepoužívá, pouze je v něm ukázán způsob volání metody method1 společně s výpisem návratové hodnoty této metody:

def test1():
    app = Application()
    print("method1 returns: {v}".format(v=app.method1()))

Po spuštění tohoto testu by se na standardní výstup měly vypsat následující řádky oznamující, že se z první metody volá metoda druhá:

method1 called
method2 called
method1 returns: method 2

9. Mockování nepřímo volané metody

Nyní se již dostáváme k popisu mockování metod. Opět si musíme uvědomit, že je zapotřebí zadat plné jméno metody, a to podle toho, v jakém kontextu bude tato metoda volána. Vzhledem k tomu, že mockujeme metodu se jménem Application.method2 („Application“ je jméno třídy), která bude volána nepřímo (nikoli z testu, ale z první metody method1), bude plné jméno mockované metody znít „application.Application.method2“.

Zkusme si tento test napsat:

@patch('application.Application.method2', return_value=42)
def test2(mocked_method):
    app = Application()
    print("mocked method called: {c}".format(c=mocked_method.called))
    print("method1 returns: {v}".format(v=app.method1()))
    print("mocked method called: {c}".format(c=mocked_method.called))

Výsledek po spuštění testu:

mocked method called: False
method1 called
method1 returns: 42
mocked method called: True

Vzhledem k tomu, že vlastnosti mockovaných funkcí a metod jsou prakticky stejné, můžeme metodu nahradit jiným handlerem atd. atd.:

def side_effect_handler():
    print("side_effect_handler method called")
    return -1
 
 
@patch('application.Application.method2', side_effect=side_effect_handler)
def test3(mocked_method):
    app = Application()
    print("mocked method called: {c}".format(c=mocked_method.called))
    print("method1 returns: {v}".format(v=app.method1()))
    print("mocked method called: {c}".format(c=mocked_method.called))

Výsledek po spuštění testu:

mocked method called: False
method1 called
side_effect_handler method called
method1 returns: -1
mocked method called: True
Poznámka: tento demonstrační příklad je umístěn na adrese https://github.com/tisnik/testing-in-python/tree/master/unittest_mock/mock-test6.

10. Složitější aplikace implementovaná ve větším množství modulů

Nyní ukážeme si způsob mockování funkcí u složitěji strukturované aplikace, v níž se nachází celkem tři moduly pojmenované jednoduše module1.py, module2.py a module3.py:

module1.py
module2.py
module3.py

V prvním modulu module1 nalezneme funkci nazvanou function1, která pouze na standardní výstup vypíše své jméno a zavolá funkci function2 z modulu module2. Tento modul samozřejmě musíme importovat:

from module2 import *
 
 
def function1():
    print("function1")
    return "function1 " + function2()

Druhý modul pojmenovaný module2 vypadá podobně jako modul první, ovšem nachází se v něm funkce function2 volající funkci function3 ze třetího modulu:

from module3 import *
 
 
def function2():
    print("function2")
    return "function2 " + function3()

Konečně se dostáváme ke třetímu modulu, který je nejjednodušší, protože neobsahuje žádný import, ale pouze implementaci funkce nazvané function3:

def function3():
    print("function3")
    return "function3"

Celá aplikace se spouští z modulu main.py, jehož obsah je triviální – spouští se v něm funkce z prvního zmíněného modulu:

from module1 import *
 
 
if __name__ == '__main__':
    print(function1())

Aplikaci si můžeme vyzkoušet například v debuggeru, a to poměrně jednoduše. Nejprve debugger spustíme (použijeme přitom standardní debugger Pythonu):

$ python3 -m pdb main.py 

Průběh spuštění a inicializace:

> /home/tester/temp/python/mocking-in-python/mock-test7/main.py(1)<module>()
-> from module1 import *

Dále nastavíme tzv. breakpoint (bod zastavení), a to na poslední volané funkci function3. Tato funkce není v modulu main.py a tudíž ji musíme klasifikovat celým jménem:

(Pdb) break module3.function3
 
Breakpoint 1 at /home/tester/temp/python/mocking-in-python/mock-test7/module3.py:1

Program v debuggeru spustíme příkazem continue:

(Pdb) continue
function1
function2
> /home/tester/temp/python/mocking-in-python/mock-test7/module3.py(2)function3()
-> print("function3")

A po jeho zastavení se podíváme, jak vypadají zásobníkové rámce:

(Pdb) where
  /usr/lib/python3.4/bdb.py(431)run()
-> exec(cmd, globals, locals)
  <string>(1)<module>()
  /home/tester/temp/python/mocking-in-python/mock-test7/main.py(5)<module>()
-> print(function1())
  /home/tester/temp/python/mocking-in-python/mock-test7/module1.py(6)function1()
-> return "function1 " + function2()
  /home/tester/temp/python/mocking-in-python/mock-test7/module2.py(6)function2()
-> return "function2 " + function3()
> /home/tester/temp/python/mocking-in-python/mock-test7/module3.py(2)function3()
-> print("function3")

Z předchozího výpisu je zřejmý celý řetězec volání.

11. Mockování funkcí volaných nepřímo z jiných modulů

Nyní si již můžeme ukázat, jakým způsobem lze mockovat funkce volané z jiných modulů. V našem konkrétním případě by se jednalo o tato volání:

Voláno z Volaná funkce Modul v němž je funkce definována
(testy).py function1 module1.py
module1.py function2 module2.py
module2.py function3 module3.py

Připomeňme si základní pravidlo, které platí v Pythonu při použití unittest.mock – při deklaraci mocku musíme uvést plné jméno funkce v kontextu jejího volání, tj. z jakého modulu je funkce volána a nikoli v jakém modulu je definována.

Zkusme si tedy napsat testovací skript test.py. Jeho začátek je „klasický“:

from unittest.mock import *
 
from module1 import *

První jednotkový test test1 bude jednoduše volat funkci function1 z modulu module1:

def test1():
    print("*** test1 ***")
    value = function1()
    print("function1 returns: {v}".format(v=value))

Ve druhém testu voláme stejnou funkci, ale současně se pokusíme mockovat funkci function2 volanou z modulu module2 (což ale nebude mít žádný efekt):

@patch('module2.function2', return_value="*mocked*")
def test2(mocked_function):
    print("*** test2 ***")
    value = function1()
    print("function1 returns: {v}".format(v=value))

Třetí test již provede mockování skutečně volané funkce. Stále se jedná o funkci function2, ovšem volanou z modulu module1, což je i případ naší „reálné“ aplikace:

@patch('module1.function2', return_value="*mocked*")
def test3(mocked_function):
    print("*** test3 ***")
    value = function1()
    print("function1 returns: {v}".format(v=value))

Čtvrtý test posunuje mock o jednu úroveň dále, konkrétně na funkci function3 volanou z modulu module2:

@patch('module2.function3', return_value="*mocked*")
def test4(mocked_function):
    print("*** test4 ***")
    value = function1()
    print("function1 returns: {v}".format(v=value))

A konečně se pokusíme taktéž mockovat funkci function3, ovšem tentokrát volanou z modulu module3, což ve skutečnosti nikdy nenastane (to však testovací framework neoznámí!):

@patch('module3.function3', return_value="*mocked*")
def test5(mocked_function):
    print("*** test5 ***")
    value = function1()
    print("function1 returns: {v}".format(v=value))

Poslední část skriptu pouze testy spustí bez dalších triků:

if __name__ == '__main__':
    test1()
    print()
 
    test2()
    print()
 
    test3()
    print()
 
    test4()
    print()
 
    test5()
    print()
Poznámka: tento demonstrační příklad je umístěn na adrese https://github.com/tisnik/testing-in-python/tree/master/unittest_mock/mock-test7.

12. Výsledek spuštění testů

Podívejme se nyní na výsledky, které získáme po spuštění testů definovaných v předchozím demonstračním příkladu. Vlastní spuštění je jednoduché, protože postačuje spustit skript nazvaný test (ten spustí interpret Pythonu a předá mu skript test.py):

$ ./test

První test test1 ve skutečnosti žádné mockování nepoužívá, takže se funkce spustí v pořadí module1.function1module2.function2module3.function3:

*** test1 ***
function1
function2
function3
function1 returns: function1 function2 function3

Ve druhém testu jsme se snažili mockovat funkci module2.function2, ovšem ve skutečnosti se tímto způsobem žádná funkce nevolá (voláme sice function2, ovšem v kontextu prvního modulu), takže výsledek bude stejný, jako v příkladu předchozím:

*** test2 ***
function1
function2
function3
function1 returns: function1 function2 function3

Teprve ve třetím testu, v němž byl mock nastaven na „module1.function2“ se namísto funkce module2.function2 použila nastavená návratová hodnota „*mocked*“. Třetí funkce se pochopitelně vůbec nezavolá:

*** test3 ***
function1
function1 returns: function1 *mocked*

Čtvrtý příklad je obdobný, ovšem s tím rozdílem, že se mock použil namísto funkce module3.function3, ovšem – to je důležité – v kontextu druhého modulu, nikoli modulu třetího:

*** test4 ***
function1
function2
function1 returns: function1 function2 *mocked*

A konečně v posledním testu byla mockována funkce function3 v kontextu modulu module3, což je sice korektní, ovšem v tomto kontextu žádná funkce zavolána není, takže výsledek je následující:

*** test5 ***
function1
function2
function3
function1 returns: function1 function2 function3

13. Mockování funkce přímo volané z testů

V demonstračním příkladu, s nímž jsme se seznámili v předchozích kapitolách, se modul nazvaný module1 do testovacího modulu importoval tímto způsobem:

from module1 import *

To je samozřejmě zcela legální způsob, ovšem má jednu nevýhodu – všechny funkce a třídy z modulu module1 se stanou součástí jmenného prostoru testů, takže se při tvorbě mocků těchto funkcí/tříd dostaneme do zbytečných problémů. Praktičtější bude import nepatrně změnit a použít následující řádek:

import module1

Nyní je již možné velmi jednoduše mockovat funkci function1 volanou v kontextu modulu module1, protože přesně takto k této funkci budeme muset přistupovat:

@patch('module1.function1', return_value="*mocked*")
def test1(mocked_function):
    print("*** test1 ***")
    value = module1.function1()
    print("function1 returns: {v}".format(v=value))

Podobným způsobem je možné zabezpečit mockování dalších funkcí, tentokrát již volaných nepřímo. Povšimněte si, že všechny další anotace @patch jsou shodné s prvním demonstračním příkladem:

@patch('module2.function2', return_value="*mocked*")
def test2(mocked_function):
    print("*** test2 ***")
    value = module1.function1()
    print("function1 returns: {v}".format(v=value))
 
 
@patch('module1.function2', return_value="*mocked*")
def test3(mocked_function):
    print("*** test3 ***")
    value = module1.function1()
    print("function1 returns: {v}".format(v=value))
 
 
@patch('module2.function3', return_value="*mocked*")
def test4(mocked_function):
    print("*** test4 ***")
    value = module1.function1()
    print("function1 returns: {v}".format(v=value))
 
 
@patch('module3.function3', return_value="*mocked*")
def test5(mocked_function):
    print("*** test5 ***")
    value = module1.function1()
    print("function1 returns: {v}".format(v=value))

I spuštění testů je pochopitelně stejné (zde se nic nezměnilo):

if __name__ == '__main__':
    test1()
    print()
 
    test2()
    print()
 
    test3()
    print()
 
    test4()
    print()
 
    test5()
    print()
Poznámka: tento demonstrační příklad je umístěn na adrese https://github.com/tisnik/testing-in-python/tree/master/unittest_mock/mock-test8.

14. Výsledek spuštění testů

Pokud tento demonstrační příklad spustíme, zjistíme snadno, že je skutečně možné mockovat i funkci pojmenovanou function1 z modulu module1 (viz první dva řádky výpisu):

*** test1 ***
function1 returns: *mocked*

Další zprávy vypisované v testech jsou již shodné s prvním příkladem:

*** test2 ***
function1
function2
function3
function1 returns: function1 function2 function3
 
*** test3 ***
function1
function1 returns: function1 *mocked*
 
*** test4 ***
function1
function2
function1 returns: function1 function2 *mocked*
 
*** test5 ***
function1
function2
function3
function1 returns: function1 function2 function3

15. Přímé použití konstruktoru patch() v těle testů

V některých případech není možné vystačit s tím, že se před testovací funkci napíše anotace @patch. Můžeme se totiž dostat do situace, kdy budeme jednou potřebovat zavolat funkci původní a jindy (v tom samém testu) mock této funkce. I toto chování je samozřejmě podporováno, protože namísto nám již známého zápisu:

@patch('module1.function1', return_value="*mocked*")
def test1(mocked_function):
    print("*** test1 ***")
    value = module1.function1()
    print("function1 returns: {v}".format(v=value))

Je možné použít přímé volání funkce patch importované z modulu unittest. Typicky se volání funkce patch používá společně s řídicí konstrukcí with, která omezuje kontext, v němž je mock platný (dnes se pravděpodobně jedná o idiomatický způsob použití). Podívejme se na příklad:

def test1():
    with patch("module1.function1", return_value="*mocked"):
        print("*** test1 ***")
        value = module1.function1()
        print("function1 returns: {v}".format(v=value))

Podobným způsobem lze zapsat i další testovací funkce. Výsledky testů budou shodné s výsledky předchozího příkladu:

*** test1 ***
function1 returns: *mocked
 
*** test2 ***
function1
function2
function3
function1 returns: function1 function2 function3
 
*** test3 ***
function1
function1 returns: function1 *mocked
 
*** test4 ***
function1
function2
function1 returns: function1 function2 *mocked
 
*** test5 ***
function1
function2
function3
function1 returns: function1 function2 function3

16. Další možnosti nabízené objekty Mock

Ve druhé kapitole jsme si řekli, že je velmi snadné zjistit, jestli je mockovaná funkce volána či nikoli. To lze samozřejmě provést i ve chvíli, kdy nepoužijeme anotaci @patch, ale namísto toho přímo zavoláme funkci patch v bloku with (předchozí kapitola). Co ovšem musíme doplnit je jméno proměnné obsahující referenci na mock. Tato reference je vrácena funkcí patch, ovšem kvůli jejímu volání v bloku with je syntaxe zápisu nepatrně odlišná:

with patch("jméno_modulu.jméno_funkce") as jméno_proměnné_s_referencí_na mock:
    ...
    ...
    ...

Ve chvíli, kdy máme referenci na mock, můžeme zjistit, zda byl volán přečtením vlastnosti called. Příklad použití pro první test:

def test1():
    with patch("module1.function1") as mocked_function:
        mocked_function.return_value = "*mocked*"
 
        print("*** test1 ***")
        value = module1.function1()
        print("function1 returns: {v}".format(v=value))
        print("mocked function called: {c}".format(c=mocked_function.called))

I zbylé testy budou vypadat podobně. Podívejme se ještě na výsledky těchto testů.

*** test1 ***
function1 returns: *mocked*
mocked function called: True

U druhého testu k volání mocku nedošlo (což již nepřímo víme z výsledné hodnoty vrácené funkcí function1):

*** test2 ***
function1
function2
function3
function1 returns: function1 function2 function3
mocked function called: False

V dalších dvou testech se mockovaná funkce volala:

*** test3 ***
function1
function1 returns: function1 *mocked*
mocked function called: True

*** test4 ***
function1
function2
function1 returns: function1 function2 *mocked*
mocked function called: True

V posledním testu však již opět ne:

*** test5 ***
function1
function2
function3
function1 returns: function1 function2 function3
mocked function called: False

Tyto postupy naleznete v příkladu dostupném na adrese https://github.com/tisnik/testing-in-python/tree/master/unittest_mock/mock-test9.

17. Zjištění kolikrát a s jakými parametry byla mockovaná funkce zavolána

Další vlastnost je při testování taktéž nemálo užitečná. Zavoláním mock.assert_called_with(hodnota1, hodnota2, …) je totiž možné zjistit, zda vůbec a s jakými parametry je mock zavolán. To však není zdaleka vše, protože ve vlastnosti mock_calls je uložena sekvence všech volání. Z této sekvence zjistíme jak pořadí volání mocku, tak i hodnoty parametrů, které byly při volání použity. V dalším testu budeme mockovat tuto funkci:

def add(x, y):
    return add_implementation(x, y)

První test může vypadat následovně – nejdříve mock zavoláme, následně vypíšeme informaci o tom, zda byl skutečně zavolán, posléze otestujeme, jestli se použili parametry 1 a 2 (popř. při druhém volání 100 a 100) a konečně si necháme vypsat seznam všech volání dané funkce:

def test1():
    print("*** test1 ***")
 
    with patch("module1.add_implementation") as mocked_function:
        mocked_function.return_value = 42
 
        value = module1.add(1, 2)
        print("add returns: {v}".format(v=value))
        print("mocked function called: {c}".format(c=mocked_function.called))
        mocked_function.assert_called_with(1, 2)
 
        value = module1.add(100, 100)
        print("add returns: {v}".format(v=value))
        print("mocked function called: {c}".format(c=mocked_function.called))
        mocked_function.assert_called_with(100, 100)
 
        print("calls: ", mocked_function.mock_calls)

Naproti tomu druhý test je schválně napsán takovým způsobem, aby se při kontrole zjistilo, že mock byl sice volán, ale s neočekávanými parametry. Ve skutečnosti totiž voláme funkci s parametry 1 a 2, ale očekáváme volání s parametry 1 a 1:

def test2():
    print("*** test2 ***")
 
    with patch("module1.add_implementation") as mocked_function:
        mocked_function.return_value = 42
 
        value = module1.add(1, 2)
        print("add returns: {v}".format(v=value))
        print("mocked function called: {c}".format(c=mocked_function.called))
        mocked_function.assert_called_with(1, 1)

Nejzajímavější je samozřejmě výsledek spuštění testů. V prvním testu se skutečně mockovaná funkce volala, a to dokonce dvakrát – poprvé s parametry 1, 2, podruhé s parametry 100, 100:

*** test1 ***
add returns: 42
mocked function called: True
add returns: 42
mocked function called: True
calls:  [call(1, 2), call(100, 100)]

U druhého testu však dojde k pádu, protože se mock nezavolal ani jednou, což kontrola velmi rychle odhalí:

ict ve školství 24

*** test2 ***
add returns: 42
mocked function called: True
Traceback (most recent call last):
  File "test.py", line 41, in
    test2()
  File "test.py", line 34, in test2
    mocked_function.assert_called_with(1, 1)
  File "/usr/lib/python3.4/unittest/mock.py", line 771, in assert_called_with
    raise AssertionError(_error_message()) from cause
AssertionError: Expected call: add_implementation(1, 1)
Actual call: add_implementation(1, 2)

18. Repositář s demonstračními příklady

Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do nového Git repositáře, který je dostupný na adrese https://github.com/tisnik/testing-in-python. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně deseti kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady a jejich části, které naleznete v následující tabulce:

# Příklad Stručný popis Cesta
1 application.py implementace logiky aplikace, kterou budeme testovat https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test3/application.py
2 main.py vstupní bod do testované aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test3/main.py
3 test.py implementace jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test3/test.py
4 run skript pro spuštění aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test3/run
5 test skript pro spuštění jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test3/test
       
6 application.py implementace logiky aplikace, kterou budeme testovat https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test4/application.py
7 main.py vstupní bod do testované aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test4/main.py
8 test.py implementace jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test4/test.py
9 run skript pro spuštění aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test4/run
10 test skript pro spuštění jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test4/test
       
11 application.py implementace logiky aplikace, kterou budeme testovat https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test5/application.py
12 main.py vstupní bod do testované aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test5/main.py
13 test.py implementace jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test5/test.py
14 run skript pro spuštění aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test5/run
15 test skript pro spuštění jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test5/test
       
16 application.py implementace logiky aplikace, kterou budeme testovat https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test6/application.py
17 main.py vstupní bod do testované aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test6/main.py
18 test.py implementace jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test6/test.py
19 run skript pro spuštění aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test6/run
20 test skript pro spuštění jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test6/test
       
21 main.py vstupní bod do testované aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test7/main.py
22 module1.py první modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test7/module1.py
23 module2.py druhý modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test7/module2.py
24 module3.py třetí modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test7/module3.py
25 test.py implementace jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test7/test.py
26 run skript pro spuštění aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test7/run
27 test skript pro spuštění jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test7/test
       
28 main.py vstupní bod do testované aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test8/main.py
29 module1.py první modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test8/module1.py
30 module2.py druhý modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test8/module2.py
31 module3.py třetí modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test8/module3.py
32 test.py implementace jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test8/test.py
33 run skript pro spuštění aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test8/run
34 test skript pro spuštění jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test8/test
       
35 main.py vstupní bod do testované aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test9/main.py
36 module1.py první modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test9/module1.py
37 module2.py druhý modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test9/module2.py
38 module3.py třetí modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test9/module3.py
39 test.py implementace jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test9/test.py
40 run skript pro spuštění aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test9/run
41 test skript pro spuštění jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-test9/test
       
42 main.py vstupní bod do testované aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testA/main.py
43 module1.py první modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testA/module1.py
44 module2.py druhý modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testA/module2.py
45 module3.py třetí modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testA/module3.py
46 test.py implementace jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testA/test.py
47 run skript pro spuštění aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testA/run
48 test skript pro spuštění jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testA/test
       
49 main.py vstupní bod do testované aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testB/main.py
50 module1.py první modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testB/module1.py
51 module2.py druhý modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testB/module2.py
52 module3.py třetí modul https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testB/module3.py
53 test.py implementace jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testB/test.py
54 run skript pro spuštění aplikace https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testB/run
55 test skript pro spuštění jednotkových testů https://github.com/tisnik/testing-in-python/blob/master/unittest_mock/mock-testB/test

19. Předchozí články s tématem testování (nejenom) v Pythonu

Tématem testování jsme se již na stránkách Rootu několikrát zabývali. Jedná se mj. o následující články:

  1. Behavior-driven development v Pythonu s využitím knihovny Behave
    https://www.root.cz/clanky/behavior-driven-development-v-pythonu-s-vyuzitim-knihovny-behave/
  2. Behavior-driven development v Pythonu s využitím knihovny Behave (druhá část)
    https://www.root.cz/clanky/behavior-driven-development-v-pythonu-s-vyuzitim-knihovny-behave-druha-cast/
  3. Behavior-driven development v Pythonu s využitím knihovny Behave (závěrečná část)
    https://www.root.cz/clanky/behavior-driven-development-v-pythonu-s-vyuzitim-knihovny-behave-zaverecna-cast/
  4. Validace datových struktur v Pythonu pomocí knihoven Schemagic a Schema
    https://www.root.cz/clanky/validace-datovych-struktur-v-pythonu-pomoci-knihoven-schemagic-a-schema/
  5. Validace datových struktur v Pythonu (2. část)
    https://www.root.cz/clanky/validace-datovych-struktur-v-pythonu-2-cast/
  6. Validace datových struktur v Pythonu (dokončení)
    https://www.root.cz/clanky/validace-datovych-struktur-v-pythonu-dokonceni/
  7. Univerzální testovací nástroj Robot Framework
    https://www.root.cz/clanky/univerzalni-testovaci-nastroj-robot-framework/
  8. Univerzální testovací nástroj Robot Framework a BDD testy
    https://www.root.cz/clanky/univerzalni-testovaci-nastroj-robot-framework-a-bdd-testy/
  9. Úvod do problematiky fuzzingu a fuzz testování
    https://www.root.cz/clanky/uvod-do-problematiky-fuzzingu-a-fuzz-testovani/
  10. Úvod do problematiky fuzzingu a fuzz testování – složení vlastního fuzzeru
    https://www.root.cz/clanky/uvod-do-problematiky-fuzzingu-a-fuzz-testovani-slozeni-vlastniho-fuzzeru/
  11. Knihovny a moduly usnadňující testování aplikací naprogramovaných v jazyce Clojure
    https://www.root.cz/clanky/knihovny-a-moduly-usnadnujici-testovani-aplikaci-naprogramovanych-v-jazyce-clojure/
  12. Validace dat s využitím knihovny spec v Clojure 1.9.0
    https://www.root.cz/clanky/validace-dat-s-vyuzitim-knihovny-spec-v-clojure-1–9–0/
  13. Testování aplikací naprogramovaných v jazyce Go
    https://www.root.cz/clanky/testovani-aplikaci-naprogramovanych-v-jazyce-go/
  14. Knihovny určené pro tvorbu testů v programovacím jazyce Go
    https://www.root.cz/clanky/knihovny-urcene-pro-tvorbu-testu-v-programovacim-jazyce-go/
  15. Testování aplikací psaných v Go s využitím knihoven Goblin a Frisby
    https://www.root.cz/clanky/testovani-aplikaci-psanych-v-go-s-vyuzitim-knihoven-goblin-a-frisby/
  16. Testování Go aplikací s využitím knihovny GΩmega a frameworku Ginkgo
    https://www.root.cz/clanky/testovani-go-aplikaci-s-vyuzitim-knihovny-gomega-mega-a-frameworku-ginkgo/
  17. Tvorba BDD testů s využitím jazyka Go a nástroje godog
    https://www.root.cz/clanky/tvorba-bdd-testu-s-vyuzitim-jazyka-go-a-nastroje-godog/
  18. Použití Go pro automatizaci práce s aplikacemi s interaktivním příkazovým řádkem
    https://www.root.cz/clanky/pouziti-go-pro-automatizaci-prace-s-aplikacemi-s-interaktivnim-prikazovym-radkem/
  19. Použití Go pro automatizaci práce s aplikacemi s interaktivním příkazovým řádkem (dokončení)
    https://www.root.cz/clanky/pouziti-go-pro-automatizaci-prace-s-aplikacemi-s-interaktivnim-prikazovym-radkem-dokonceni/
  20. Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure
    https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure/
  21. Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure (2)
    https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure-2/

20. Odkazy na Internetu

  1. Awesome Python – testing
    https://github.com/vinta/awesome-python#testing
  2. Selenium (pro Python)
    https://pypi.org/project/selenium/
  3. Getting Started With Testing in Python
    https://realpython.com/python-testing/
  4. unittest.mock — mock object library
    https://docs.python.org/3­.5/library/unittest.mock.html
  5. mock 2.0.0
    https://pypi.python.org/pypi/mock
  6. An Introduction to Mocking in Python
    https://www.toptal.com/python/an-introduction-to-mocking-in-python
  7. Mock – Mocking and Testing Library
    http://mock.readthedocs.io/en/stable/
  8. Python Mocking 101: Fake It Before You Make It
    https://blog.fugue.co/2016–02–11-python-mocking-101.html
  9. Nauč se Python! – Testování
    http://naucse.python.cz/les­sons/intro/testing/
  10. Flexmock (dokumentace)
    https://flexmock.readthedoc­s.io/en/latest/
  11. Test Fixture (Wikipedia)
    https://en.wikipedia.org/wi­ki/Test_fixture
  12. Mock object (Wikipedia)
    https://en.wikipedia.org/wi­ki/Mock_object
  13. Extrémní programování
    https://cs.wikipedia.org/wi­ki/Extr%C3%A9mn%C3%AD_pro­gramov%C3%A1n%C3%AD
  14. Programování řízené testy
    https://cs.wikipedia.org/wi­ki/Programov%C3%A1n%C3%AD_%C5%99%­C3%ADzen%C3%A9_testy
  15. Pip (dokumentace)
    https://pip.pypa.io/en/stable/
  16. Tox
    https://tox.readthedocs.io/en/latest/
  17. pytest: helps you write better programs
    https://docs.pytest.org/en/latest/
  18. doctest — Test interactive Python examples
    https://docs.python.org/dev/li­brary/doctest.html#module-doctest
  19. unittest — Unit testing framework
    https://docs.python.org/dev/li­brary/unittest.html
  20. Python namespaces
    https://bytebaker.com/2008/07/30/pyt­hon-namespaces/
  21. Namespaces and Scopes
    https://www.python-course.eu/namespaces.php
  22. Stránka projektu Robot Framework
    https://robotframework.org/
  23. GitHub repositář Robot Frameworku
    https://github.com/robotfra­mework/robotframework
  24. Robot Framework (Wikipedia)
    https://en.wikipedia.org/wi­ki/Robot_Framework
  25. Tutoriál Robot Frameworku
    http://www.robotframeworktu­torial.com/
  26. Robot Framework Documentation
    https://robotframework.or­g/robotframework/
  27. Robot Framework Introduction
    https://blog.testproject.i­o/2016/11/22/robot-framework-introduction/
  28. robotframework 3.1.2 na PyPi
    https://pypi.org/project/ro­botframework/
  29. Robot Framework demo (GitHub)
    https://github.com/robotfra­mework/RobotDemo
  30. Robot Framework web testing demo using SeleniumLibrary
    https://github.com/robotfra­mework/WebDemo
  31. Robot Framework for Mobile Test Automation Demo
    https://www.youtube.com/wat­ch?v=06LsU08slP8
  32. Gherkin
    https://cucumber.io/docs/gherkin/
  33. Selenium
    https://selenium.dev/
  34. SeleniumLibrary
    https://robotframework.org/
  35. The Practical Test Pyramid
    https://martinfowler.com/ar­ticles/practical-test-pyramid.html
  36. Acceptance Tests and the Testing Pyramid
    http://www.blog.acceptance­testdrivendevelopment.com/ac­ceptance-tests-and-the-testing-pyramid/
  37. Tab-separated values
    https://en.wikipedia.org/wiki/Tab-separated_values
  38. A quick guide about Python implementations
    https://blog.rmotr.com/a-quick-guide-about-python-implementations-aa224109f321
  39. radamsa
    https://gitlab.com/akihe/radamsa
  40. Fuzzing (Wikipedia)
    https://en.wikipedia.org/wiki/Fuzzing
  41. american fuzzy lop
    http://lcamtuf.coredump.cx/afl/
  42. Fuzzing: the new unit testing
    https://go-talks.appspot.com/github.com/dvyukov/go-fuzz/slides/fuzzing.slide#1
  43. Corpus for github.com/dvyukov/go-fuzz examples
    https://github.com/dvyukov/go-fuzz-corpus
  44. AFL – QuickStartGuide.txt
    https://github.com/google/AF­L/blob/master/docs/QuickStar­tGuide.txt
  45. Introduction to Fuzzing in Python with AFL
    https://alexgaynor.net/2015/a­pr/13/introduction-to-fuzzing-in-python-with-afl/
  46. Writing a Simple Fuzzer in Python
    https://jmcph4.github.io/2018/01/19/wri­ting-a-simple-fuzzer-in-python/
  47. How to Fuzz Go Code with go-fuzz (Continuously)
    https://fuzzit.dev/2019/10/02/how-to-fuzz-go-code-with-go-fuzz-continuously/
  48. Golang Fuzzing: A go-fuzz Tutorial and Example
    http://networkbit.ch/golang-fuzzing/
  49. Fuzzing Python Modules
    https://stackoverflow.com/qu­estions/20749026/fuzzing-python-modules
  50. 0×3 Python Tutorial: Fuzzer
    http://www.primalsecurity.net/0×3-python-tutorial-fuzzer/
  51. fuzzing na PyPi
    https://pypi.org/project/fuzzing/
  52. Fuzzing 0.3.2 documentation
    https://fuzzing.readthedoc­s.io/en/latest/
  53. Randomized testing for Go
    https://github.com/dvyukov/go-fuzz
  54. HTTP/2 fuzzer written in Golang
    https://github.com/c0nrad/http2fuzz
  55. Ffuf (Fuzz Faster U Fool) – An Open Source Fast Web Fuzzing Tool
    https://hacknews.co/hacking-tools/20191208/ffuf-fuzz-faster-u-fool-an-open-source-fast-web-fuzzing-tool.html
  56. Continuous Fuzzing Made Simple
    https://fuzzit.dev/
  57. Halt and Catch Fire
    https://en.wikipedia.org/wi­ki/Halt_and_Catch_Fire#In­tel_x86
  58. Random testing
    https://en.wikipedia.org/wi­ki/Random_testing
  59. Monkey testing
    https://en.wikipedia.org/wi­ki/Monkey_testing
  60. Fuzzing for Software Security Testing and Quality Assurance, Second Edition
    https://books.google.at/bo­oks?id=tKN5DwAAQBAJ&pg=PR15&lpg=PR15&q=%­22I+settled+on+the+term+fuz­z%22&redir_esc=y&hl=de#v=o­nepage&q=%22I%20settled%20on%20the%20ter­m%20fuzz%22&f=false
  61. libFuzzer – a library for coverage-guided fuzz testing
    https://llvm.org/docs/LibFuzzer.html
  62. fuzzy-swagger na PyPi
    https://pypi.org/project/fuzzy-swagger/
  63. fuzzy-swagger na GitHubu
    https://github.com/namuan/fuzzy-swagger
  64. Fuzz testing tools for Python
    https://wiki.python.org/mo­in/PythonTestingToolsTaxo­nomy#Fuzz_Testing_Tools
  65. A curated list of awesome Go frameworks, libraries and software
    https://github.com/avelino/awesome-go
  66. gofuzz: a library for populating go objects with random values
    https://github.com/google/gofuzz
  67. tavor: A generic fuzzing and delta-debugging framework
    https://github.com/zimmski/tavor
  68. hypothesis na GitHubu
    https://github.com/Hypothe­sisWorks/hypothesis
  69. Hypothesis: Test faster, fix more
    https://hypothesis.works/
  70. Hypothesis
    https://hypothesis.works/ar­ticles/intro/
  71. What is Hypothesis?
    https://hypothesis.works/articles/what-is-hypothesis/
  72. Databáze CVE
    https://www.cvedetails.com/
  73. Fuzz test Python modules with libFuzzer
    https://github.com/eerimoq/pyfuzzer
  74. Taof – The art of fuzzing
    https://sourceforge.net/pro­jects/taof/
  75. JQF + Zest: Coverage-guided semantic fuzzing for Java
    https://github.com/rohanpadhye/jqf
  76. http2fuzz
    https://github.com/c0nrad/http2fuzz
  77. Demystifying hypothesis testing with simple Python examples
    https://towardsdatascience­.com/demystifying-hypothesis-testing-with-simple-python-examples-4997ad3c5294
  78. Testování
    http://voho.eu/wiki/testovani/
  79. Unit testing (Wikipedia.en)
    https://en.wikipedia.org/wi­ki/Unit_testing
  80. Unit testing (Wikipedia.cz)
    https://cs.wikipedia.org/wi­ki/Unit_testing
  81. Unit Test vs Integration Test
    https://www.youtube.com/wat­ch?v=0GypdsJulKE
  82. TestDouble
    https://martinfowler.com/bli­ki/TestDouble.html
  83. Test Double
    http://xunitpatterns.com/Tes­t%20Double.html
  84. Test-driven development (Wikipedia)
    https://en.wikipedia.org/wiki/Test-driven_development
  85. Acceptance test–driven development
    https://en.wikipedia.org/wi­ki/Acceptance_test%E2%80%93dri­ven_development
  86. Gauge
    https://gauge.org/
  87. Gauge (software)
    https://en.wikipedia.org/wi­ki/Gauge_(software)
  88. PYPL PopularitY of Programming Language
    https://pypl.github.io/PYPL.html
  89. Testing is Good. Pyramids are Bad. Ice Cream Cones are the Worst
    https://medium.com/@fistsOf­Reason/testing-is-good-pyramids-are-bad-ice-cream-cones-are-the-worst-ad94b9b2f05f
  90. Články a zprávičky věnující se Pythonu
    https://www.root.cz/n/python/
  91. PythonTestingToolsTaxonomy
    https://wiki.python.org/mo­in/PythonTestingToolsTaxo­nomy
  92. Top 6 BEST Python Testing Frameworks [Updated 2020 List]
    https://www.softwaretestin­ghelp.com/python-testing-frameworks/

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.