Hlavní navigace

Testování aplikací s využitím nástroje Hypothesis (dokončení)

 Autor: Depositphotos
V deváté části seriálu o tvorbě testů s využitím programovacího jazyka Python dokončíme popis některých možností poskytovaných knihovnou Hypothesis při generování dat pro jednotkové testy i při zpracování výsledků testů.
Pavel Tišnovský 16. 6. 2020
Doba čtení: 32 minut

Sdílet

11. Další příklady použití regulárních výrazů v testech

12. Generátor dat pro kód používající knihovnu NumPy

13. Vícerozměrná pole

14. Pole pravdivostních hodnot

15. Trojrozměrná pole s prvky typu half

16. Bližší specifikace hodnot prvků v generovaných polích

17. Závěr

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. Test výpočtu faktoriálu

V úvodní kapitole si připomeneme, jakým způsobem jsou vlastně testy vytvářené s využitím nástroje Hypothesis konstruovány. Minule jsme v demonstračních příkladech používali algoritmus pro bublinkové řazení a taktéž jednoduchou šifru typu ROT-13, takže si dnes pro změnu ukážeme odlišný algoritmus. Bude se jednat o „školní“ výpočet faktoriálu založený na použití rekurze. S tímto algoritmem jsme se již setkali při popisu nástroje Mypy:

"""Výpočet faktoriálu."""
 
 
def factorial(n):
    """Rekurzivní výpočet faktoriálu."""
    assert isinstance(n, int), "Integer expected"
 
    if n < 0:
        return None
    if n == 0:
        return 1
    result = n * factorial(n-1)
 
    assert isinstance(result, int), "Internal error in factorial computation"
    return result

Jednoduchý test s hypotézou může být založen na faktu, že faktoriál by měl být kladné číslo a současně je jeho hodnota větší nebo rovna vstupu. Jedná se o značně neurčitý test, ale jedná se prozatím o první krok:

"""Jednotkové testy pro výpočet faktoriálu."""
 
from hypothesis import given
from hypothesis.strategies import integers
 
from factorial import factorial
 
 
@given(integers())
def test_factorial(value):
    """Jednotkový test pro výpočet faktoriálu."""
    assert factorial(value) > 0
    assert factorial(value) >= value

Pokus o spuštění testů:

$ pytest -v

však povede k pádu, a to z toho důvodu, že jsme prozatím nepočítali s tím, jak jsou ošetřovány záporné vstupy:

============================= test session starts ==============================
platform linux -- Python 3.6.6, pytest-5.4.2, py-1.5.2, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/home/ptisnovs/src/python/testing-in-python/hypothesis/factorial_1/.hypothesis/examples')
rootdir: /home/ptisnovs/src/python/testing-in-python/hypothesis/factorial_1
plugins: print-0.1.3, voluptuous-1.0.2, hypothesis-5.16.0, cov-2.5.1
collecting ... collected 1 item
 
factorial_test.py::test_factorial FAILED                                 [100%]
 
=================================== FAILURES ===================================
________________________________ test_factorial ________________________________
 
    @given(integers())
>   def test_factorial(value):
 
factorial_test.py:10:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
 
value = -1
 
    @given(integers())
    def test_factorial(value):
        """Jednotkový test pro výpočet faktoriálu."""
>       assert factorial(value) > 0
E       TypeError: '>' not supported between instances of 'NoneType' and 'int'
 
factorial_test.py:12: TypeError
---------------------------------- Hypothesis ----------------------------------
Falsifying example: test_factorial(
    value=-1,
)
=========================== short test summary info ============================
FAILED factorial_test.py::test_factorial - TypeError: '>' not supported betwe...
============================== 1 failed in 0.07s ===============================

2. Omezení vstupních hodnot v testech

Testy však pochopitelně můžeme upravit, například takovým způsobem, aby se pro kladné hodnoty a nulu používal již v předchozí kapitole popsaný test se dvěma hypotézami a pro hodnoty záporné naopak test na výslednou hodnotu None. Rozsah generovaných vstupů lze velmi snadno omezit s využitím nepovinných parametrů min_value a max_value předávaných konstruktoru integers:

"""Jednotkové testy pro výpočet faktoriálu."""
 
from hypothesis import given
from hypothesis.strategies import integers
 
from factorial import factorial
 
 
@given(integers(min_value=0))
def test_factorial(value):
    """Jednotkový test pro výpočet faktoriálu."""
    assert factorial(value) > 0
    assert factorial(value) >= value
 
 
@given(integers(max_value=-1))
def test_factorial(value):
    """Jednotkový test pro výpočet faktoriálu."""
    assert factorial(value) is None

Nyní již otestování proběhne s pořádku, i když stále nevíme, zda se vůbec počítá správný faktoriál či zda se pouze například nevrací původní hodnota (pro kladné vstupy):

$ pytest -v
 
============================= test session starts ==============================
platform linux -- Python 3.6.6, pytest-5.4.2, py-1.5.2, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/home/ptisnovs/src/python/testing-in-python/hypothesis/factorial_2/.hypothesis/examples')
rootdir: /home/ptisnovs/src/python/testing-in-python/hypothesis/factorial_2
plugins: print-0.1.3, voluptuous-1.0.2, hypothesis-5.16.0, cov-2.5.1
collecting ... collected 1 item
 
factorial_test.py::test_factorial PASSED                                 [100%]
 
============================== 1 passed in 0.11s ===============================

3. Využití metody filter ve strategiích

Už v předchozím článku jsme si ukázali, že při generování vstupních hodnot můžeme použít i metodu filter, která hodnoty omezí na základě nějaké zadané podmínky či podmínek. I mimo testy si můžeme chování této metody ověřit:

from hypothesis.strategies import lists, integers
 
g = lists(integers().filter(lambda x: x > 0 and x % 2 == 0))
 
for _ in range(10):
    print(g.example())

Příklad výsledku (bude se lišit v každém spuštění, protože hodnoty jsou generovány pseudonáhodně):

[]
[]
[]
[114, 297635958, 36382594596201776729035817479773596128]
[]
[]
[1584, 20756, 27064]
[]
[]
[6256, 16432]

Můžeme se tedy pokusit generovat celá čísla z plného rozsahu (daného typu v Pythonu) a následně generované hodnoty filtrovat – poprvé použijeme jen čísla větší nebo rovna nule a podruhé pouze záporná čísla:

"""Jednotkové testy pro výpočet faktoriálu."""
 
from hypothesis import given
from hypothesis.strategies import integers
 
from factorial import factorial
 
 
@given(integers().filter(lambda x: x >= 0))
def test_factorial(value):
    """Jednotkový test pro výpočet faktoriálu."""
    assert factorial(value) > 0
    assert factorial(value) >= value
 
 
@given(integers().filter(lambda x: x < 0))
def test_factorial(value):
    """Jednotkový test pro výpočet faktoriálu."""
    assert factorial(value) is None

Testy by opět měly projít bez chyby, ale možná si povšimnete, že jejich běh bude trvat delší dobu:

$ pytest -v
 
============================= test session starts ==============================
platform linux -- Python 3.6.6, pytest-5.4.2, py-1.5.2, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/home/ptisnovs/src/python/testing-in-python/hypothesis/factorial_3/.hypothesis/examples')
rootdir: /home/ptisnovs/src/python/testing-in-python/hypothesis/factorial_3
plugins: print-0.1.3, voluptuous-1.0.2, hypothesis-5.16.0, cov-2.5.1
collecting ... collected 1 item
 
factorial_test.py::test_factorial PASSED                                 [100%]
 
============================== 1 passed in 0.17s ===============================
Poznámka: tento způsob je méně efektivní, než použití min_value a max_value, na druhou stranu je ovšem obecnější, což si ostatně ukážeme v navazujících kapitolách.

4. Další demonstrační příklad – test algoritmu na existenci prvočísel

Existuje ovšem i lepší způsob použití metody filter. Můžeme se například pokusit otestovat funkci, která pro zadanou celočíselnou hodnotu vrátí logickou hodnotu True v případě, že vstup je prvočíslem a False v případě, že se jedná o číslo složené, popř. o záporné číslo. Jedna z možných implementací takové funkce může vypadat následovně:

"""Test, zda je vstupní hodnota prvočíslem."""
 
def is_prime(x):
    """Test, zda je vstupní hodnota prvočíslem."""
    if x == 2:
        return True
    if x < 2 or x % 2 == 0:
        return False
    return not any(x % y == 0 for y in range(3, int(x**0.5) + 1, 2))

První varianta testů může být založena na zjištění, zda se pro sudé hodnoty (s výjimkou čísla 2) vždy vrátí hodnota False:

"""Jednotkové testy pro funkci is_prime()."""
 
from hypothesis import given
from hypothesis.strategies import integers
 
from is_prime import is_prime
 
 
@given(integers(min_value=3).filter(lambda x: x % 2 == 0))
def test_is_prime_for_even_values(value):
    """Jednotkový test pro funkci is_prime()."""
    assert not is_prime(value)

Testy se vstupy a podmínkami generovanými nástrojem Hypothesis by měly proběhnout bez chyby:

$ pytest -v
 
============================= test session starts ==============================
platform linux -- Python 3.6.6, pytest-5.4.2, py-1.5.2, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/home/ptisnovs/src/python/testing-in-python/hypothesis/primes_1/.hypothesis/examples')
rootdir: /home/ptisnovs/src/python/testing-in-python/hypothesis/primes_1
plugins: print-0.1.3, voluptuous-1.0.2, hypothesis-5.16.0, cov-2.5.1
collecting ... collected 1 item
 
is_prime_test.py::test_is_prime_for_even_values PASSED                   [100%]
 
============================== 1 passed in 0.13s ===============================

5. Využití metody map ve strategiích

Předchozí test, v němž jsme filtrovali ze všech kladných čísel větších než 2 ty hodnoty, které jsou sudé, ovšem můžeme i otočit a naopak akceptovat všechna kladná čísla větší než 2 a tyto čísla můžeme násobit dvěma. K tomuto účelu slouží metoda map. Test tedy bude funkci is_prime předávat pseudonáhodně vybrané hodnoty z množiny (4, 6, 8, 10, …):

"""Jednotkové testy pro funkci is_prime()."""
 
from hypothesis import given
from hypothesis.strategies import integers
 
from is_prime import is_prime
 
 
@given(integers(min_value=2).map(lambda x: 2 * x))
def test_is_prime_for_even_values(value):
    """Jednotkový test pro funkci is_prime()."""
    assert not is_prime(value)

Testy by v tomto případě opět měly proběhnout bez chyby:

$ pytest -v
 
============================= test session starts ==============================
platform linux -- Python 3.6.6, pytest-5.4.2, py-1.5.2, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/home/ptisnovs/src/python/testing-in-python/hypothesis/primes_2/.hypothesis/examples')
rootdir: /home/ptisnovs/src/python/testing-in-python/hypothesis/primes_2
plugins: print-0.1.3, voluptuous-1.0.2, hypothesis-5.16.0, cov-2.5.1
collecting ... collected 1 item
 
is_prime_test.py::test_is_prime_for_even_values PASSED                   [100%]
 
============================== 1 passed in 0.11s ===============================

6. Vytvoření specifických vstupů pro test prvočísel

Pro lepší otestování funkce pro výpočet prvočísel by samozřejmě bylo lepší mít k dispozici lépe vytvořené vstupy. Pro prvních čtyřicet prvočísel existuje polynom sestavený slavným Eulerem – viz též Prime_formulas_and_polyno­mial_functions. Pokud se za x dosazují hodnoty od 0 do 39, bude výsledkem x-té prvočíslo. Test tedy můžeme (alespoň v malém rozsahu vstupů) napsat i následovně:

"""Jednotkové testy pro funkci is_prime()."""
 
from hypothesis import given
from hypothesis.strategies import integers
 
from is_prime import is_prime
 
 
@given(integers(min_value=0, max_value=39).map(lambda x: x ** 2 + x + 41))
def test_is_prime_for_even_values(value):
    """Jednotkový test pro funkci is_prime()."""
    assert is_prime(value)

Otestování by opět mělo proběhnout v pořádku.

Poznámka: podobných polynomů existuje i více, bližší popis naleznete například na stránce https://mathworld.wolfram.com/Prime-GeneratingPolynomial.html.

7. Strategie builds

Nástroj Hypothesis podporuje i strategii nazvanou builds, která umožňuje, aby byly vstupní hodnoty pro testy vytvářeny (resp. přesněji řečeno generovány) nějakým objektem nebo funkcí. Poněkud umělé použití této strategie můžeme vidět v dalším demonstračním příkladu, ve kterém se testovaná funkce is_prime volá s náhodně vybranými prvočísly. Z časových důvodů je test omezen na prvních sto prvočísel, ovšem pochopitelně je možné tuto hodnotu snadno zvýšit. Prvočísla jsou vypočtena pomocnou funkcí nazvanou generate_nth_prime, která si mezivýsledky (již vypočtená menší prvočísla) ukládá do mezipaměti reprezentovanou seznamem pojmenovaným cache. Pochopitelně se ovšem v žádném případě nejedná o rychlé ani paměťově efektivní řešení:

"""Jednotkové testy pro funkci is_prime()."""
 
from hypothesis import given
from hypothesis.strategies import integers, builds
 
from is_prime import is_prime
 
 
cache = [2, 3]
 
 
def generate_nth_prime(n):
    """Vygenerování n-tého prvočísla (lze získat z cache)."""
    if n < len(cache):
        return cache[n]
 
    x = cache[-1]
 
    while len(cache) < n:
        # zde je pochopitelně vhodné použít jiný algoritmus, než ten, který je testován!!!
        if not any(x % y == 0 for y in range(3, int(x**0.5) + 1, 2)):
            cache.append(x)
        x += 2
    return cache[-1]
 
 
@given(builds(generate_nth_prime, integers(min_value=1, max_value=100)))
def test_is_prime_for_even_values(value):
    """Jednotkový test pro funkci is_prime()."""
    assert is_prime(value)
Poznámka: funkci generate_nth_prime můžete najít v jiné podobě na internetu, ovšem pracuje chybně, což si ostatně můžete snadno ověřit. Zajímavý a pro dnešní „internety“ asi i dosti typický je fakt, že je tuto chybně napsanou funkci možné vidět hned na několika stránkách s naprosto stejnou strukturou i s totožným chybným chováním :-)

8. Testy s orákulem

O testech s orákulem jsme se zmínili minule. V případě, že není možné orákulum implementovat formou algoritmu, můžeme si v mnoha případech vypomoci předpočítanými hodnotami. A tento přístup je ukázán i v dalším demonstračním příkladu, v němž testujeme funkci pro výpočet faktoriálu oproti hodnotám, které byly získány dopředu a především jiným způsobem, než testovaným algoritmem (v tomto případě jde o dosti umělý příklad, který vlastně vůbec nevyžaduje použití Hypothesis):

"""Jednotkové testy pro výpočet faktoriálu."""
 
from hypothesis import given
from hypothesis.strategies import lists, integers
 
from factorial import factorial
 
precomputed = [
    1,
    2,
    6,
    24,
    120,
    720,
    5040,
    40320,
    362880,
    3628800,
    39916800,
    479001600,
    6227020800,
    87178291200,
    1307674368000,
    20922789888000,
    355687428096000,
    6402373705728000,
    121645100408832000,
    2432902008176640000,
    51090942171709440000,
    1124000727777607680000,
    25852016738884976640000,
    620448401733239439360000,
    15511210043330985984000000,
    403291461126605635584000000,
    10888869450418352160768000000,
    304888344611713860501504000000,
    8841761993739701954543616000000,
    265252859812191058636308480000000,
]
 
 
@given(integers(min_value=1, max_value=30))
def test_factorial(value):
    """Jednotkový test pro výpočet faktoriálu."""
    assert factorial(value) == precomputed[value]
 
 
@given(integers().filter(lambda x: x < 0))
def test_factorial(value):
    """Jednotkový test pro výpočet faktoriálu."""
    assert factorial(value) is None

9. Orákulum a test na predikát pro prvočísla

Naprosto stejným způsobem ovšem můžeme získat tabulku s prvočísly a opět posunout Hypothesis směrem ke klasickým jednotkovým testům řízeným tabulkami:

"""Jednotkové testy pro funkci is_prime()."""
 
from hypothesis import given
from hypothesis.strategies import integers, builds
 
from is_prime import is_prime
 
 
precomputed = [
    2,
    3,
    5,
    7,
    11,
    13,
    17,
    19,
    23,
    29,
    31,
    37,
    41,
    43,
    47,
    53,
    59,
    61,
    67,
    71,
    73,
    79,
    83,
    89,
    97,
    101
]
 
 
@given(integers(min_value=1, max_value=100))
def test_is_prime(value):
    """Jednotkový test pro funkci is_prime()."""
    assert is_prime(value) == (value in precomputed)

Lepší je ovšem (pokud je to pochopitelně možné – a nyní to možné je) namísto statické tabulky použít tabulku vypočtenou až do zadaného limitu. K tomuto účelu můžeme použít například algoritmus, s nímž jsme se již v tomto seriálu setkali:

"""Jednotkové testy pro funkci is_prime()."""
 
from hypothesis import given
from hypothesis.strategies import integers, builds
 
from is_prime import is_prime
 
 
# originální kód lze nalézt na adrese:
# http://www.rosettacode.org/wiki/Sieve_of_Eratosthenes#Odds-only_version_of_the_array_sieve_above
def primes(limit):
    """Výpočet seznamu prvočísel až do zadaného limitu."""
    # okrajový případ
    if limit < 2:
        return []
 
    # druhý případ - 2 je speciálním prvočíslem
    if limit < 3:
        return [2]
 
    lmtbf = (limit - 3) // 2
 
    # naplnění tabulky, která se bude prosívat
    buf = [True] * (lmtbf + 1)
 
    # vlastní prosívání
    for i in range((int(limit ** 0.5) - 3) // 2 + 1):
        if buf[i]:
            p = i + i + 3
            s = p * (i + 1) + i
            buf[s::p] = [False] * ((lmtbf - s) // p + 1)
 
    # vytvoření seznamu prvočísel
    return [2] + [i + i + 3 for i, v in enumerate(buf) if v]
 
 
LIMIT = 1000
 
precomputed = primes(LIMIT)
 
 
@given(integers(min_value=1, max_value=LIMIT))
def test_is_prime(value):
    """Jednotkový test pro funkci is_prime()."""
    assert is_prime(value) == (value in precomputed)

10. Použití regulárního výrazu definujícího vlastnosti generovaných testovacích dat

Nástroj Hypothesis nabízí i velmi mocný nástroj – možnost použití regulárního výrazu, který definuje vlastnosti generovaných testovacích dat, v tomto případě řetězců nebo polí bajtů. Všechny řetězce/pole bajtů budou regulárním výrazem akceptovány. Tuto možnost, která je velmi užitečná (generování URL, e-mailových adres atd. atd.), si nejprve ukážeme jen na velmi prostém příkladu, který ani není testem:

from hypothesis.strategies import from_regex
 
g = from_regex(r"#[a-fA-F0-9]{6}")
 
for _ in range(20):
    print(g.example())

Tento příklad vygeneruje dvacet řetězců, které obsahují část odpovídající barvě zakódované v šestici hexa číslic, tj. ve formátu, který se mj. prosadil i ve světě HTML a CSS:

#000000
#000000
#e00000
#A00000
#000000
#F00000
#200000???
#d00000
#d00000
#a00000
#A00000
fdsa#a00000
#400000
#fe0000
#000000
#e00000
#0b0000
#800000
????????????????????#Ce10DE????
#000000

Povšimněte si, že řetězce obsahují i další znaky, což je ovšem ve skutečnosti v pořádku, protože i takové řetězce (nebo jejich části) budou regulárním výrazem akceptovány.

Pokud budeme chtít vytvářet pouze řetězce akceptované regulárním výrazem jako celek, je nutné použít parametr fullmatch=True:

from hypothesis.strategies import from_regex
 
g = from_regex(r"#[a-fA-F0-9]{6}", fullmatch=True)
 
for _ in range(20):
    print(g.example())

Nyní se již vytváří řetězce obsahující kódy různých barev, což je pro testování ideální:

#c00000
#fF3D78
#a00000
#c3C4Eb
#000000
#B00000
#000000
#400000
#DC62c5
#502B12
#d6bB2B
#fDaAFa
#b00000
#F00000
#000000
#59a7F9
#000000
#0E0000
#000000
#bCdB0E

11. Další příklady použití regulárních výrazů v testech

Podívejme se ještě na několik příkladů, které jsou založeny na regulárních výrazech a taktéž na funkci from_regex. Následující regulární výraz je poměrně často používán na ověření, zda řetězec obsahuje platnou e-mailovou adresu:

[^@\s]+@[^@\s]+\.[a-zA-Z0-9]+$

Můžeme tedy jít opačným směrem a použít tento výraz pro vygenerování e-mailových adres:

from hypothesis.strategies import from_regex
 
g = from_regex(r"[^@\s]+@[^@\s]+\.[a-zA-Z0-9]+$", fullmatch=True)
 
for _ in range(20):
    print(g.example())

S těmito výsledky:

0@0.0
-%????@????#.RHb
0@0.0
0@0.0
0@0.0abc
0@0.0
'@0.0
0@0.0
0@0.0
.@0.0
0@0.0
%'????)鋕@"!&.gkQsxQ55
(@0.0
'#????+,-????$@????%????????,+-.SrQm
????????????@????!&.8f7
????@0.0
(@0.0
(@0.0
0@0.0
0@0.0

Pokud vám nevyhovuje, že se v adrese může objevit prakticky jakýkoli nebílý znak z Unicode, lze omezit sadu povolených znaků pouze na ASCII, a to nám již známým způsobem – pomocí metody filter:

from hypothesis.strategies import from_regex
 
g = from_regex(r"[^@\s]+@[^@\s]+\.[a-zA-Z0-9]+$", fullmatch=True).filter(lambda s:all(ord(c) < 128 for c in s))
 
for _ in range(20):
    print(g.example())

S výsledky:

0@0.0
0@0.0
+@0.0
0@0.0
/,@+.Uf
0@0.0
0@0.0
0@0.0
0@0.0
*@0.0
0@0.0
/@0.0
+@0.0
0@0.0
*@0.0
0@0.0
00@0.0
0@0.0
0@0.0
0@0.0
Poznámka: samozřejmě můžete specifikovat i minimální délku řetězce a další vlastnosti.

12. Generátor dat pro kód používající knihovnu NumPy

Programovací jazyk Python se velmi často používá společně s knihovnou NumPy, s níž jsme se ostatně na stránkách Rootu již seznámili. A právě z tohoto důvodu obsahuje nástroj Hypothesis možnost tvorby polí (ND-Array) specifikované velikosti, tvaru (shape) a typů prvků. V následujícím příkladu je ukázáno, jak lze vygenerovat desetiprvkové vektory s prvky typu int8, což jsou osmibitová celá čísla se znaménkem:

import numpy as np
from hypothesis.extra.numpy import arrays
 
g = arrays(np.int8, 10, elements=None)
 
for _ in range(10):
    print(g.example())

Výsledek činnosti předchozího skriptu – vektory použitelné při testování:

[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[-21 -21 -51 103 -21 -21 107 119  -1 -21]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[1 1 1 1 1 1 1 1 1 1]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[116 -58 116 116 109 116 116 116 116 116]
[-1 -1 -1 -1 -1 -1 -1 -1 -1 -1]
Poznámka: v tomto případě je druhým parametrem funkce arrays celé číslo (skalární hodnota), ovšem v dalším textu uvidíme, že se může jednat i o n-tici.

13. Vícerozměrná pole

U polí je možné kromě počtu prvků specifikovat i tvar (shape) pole. V dalším příkladu mají pole tvar matice se čtyřmi řádky a třemi sloupci, takže jejich tvar je určen n-ticí (4,3):

import numpy as np
from hypothesis.extra.numpy import arrays
 
g = arrays(np.float, (4,3), elements=None)
 
for _ in range(10):
    print(g.example())
    print()

Příklad několika výsledků:

[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
 
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
 
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
 
[[2.89039723e-147 2.89039723e-147 2.89039723e-147]
 [2.89039723e-147 2.89039723e-147 2.89039723e-147]
 [2.89039723e-147 2.89039723e-147 2.89039723e-147]
 [2.89039723e-147 2.89039723e-147 2.89039723e-147]]
 
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
 
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
 
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
 
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
 
[[-1.79769313e+308 -1.79769313e+308 -1.79769313e+308]
 [-1.79769313e+308 -1.79769313e+308 -3.08532025e+016]
 [-1.79769313e+308 -1.79769313e+308 -1.79769313e+308]
 [-1.79769313e+308 -2.84042690e+107 -1.79769313e+308]]
 
[[-5.38016682e+016 -5.38016682e+016 -1.10000000e+000]
 [-5.38016682e+016  1.32684804e+016 -5.38016682e+016]
 [-5.38016682e+016              nan -5.38016682e+016]
 [ 1.10497728e+163 -5.38016682e+016 -5.38016682e+016]]
Poznámka: povšimněte si mj. i speciálních hodnot typu nejvyšší možné číslo typu (double) či dokonce NaN. Ještě jedno upozornění – np.float skutečně odpovídá céčkovému datovému typu double, ovšem můžete namísto toho použít explicitní typy np.float32 a np.float64.

14. Pole pravdivostních hodnot

Vzhledem k tomu, že knihovna Numpy podporuje i typ „pravdivostní hodnota“ reprezentovaný identifikátorem np.bool, lze generovat i pole obsahující náhodné hodnoty tohoto typu. V tomto konkrétním případě pole o rozměrech 10×10 prvků:

import numpy as np
from hypothesis.extra.numpy import arrays
 
g = arrays(np.bool, (10,10))
 
print(g.example())

V první iteraci většinou získáme pole s poněkud nudným obsahem, ovšem v reálných testech pochopitelně budou použita pole odlišná:

[[False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]
 [False False False False False False False False False False]]

15. Trojrozměrná pole s prvky typu half

Pro algoritmy ML a AI se někdy používá i datový typ half floating point, o němž jsme se zmiňovali v článku Brain Floating Point – nový formát uložení čísel pro strojové učení a chytrá čidla. Knihovna NumPy umožňuje práci i s tímto typem, resp. přesněji řečeno s N-dimenzionálními poli, které prvky tohoto typu obsahují:

import numpy as np
from hypothesis.extra.numpy import arrays
 
g = arrays(np.half, (2,3,4), elements=None, unique=True)
 
for _ in range(10):
    print(g.example())
    print()
Poznámka: povšimněte si nepovinného parametru unique, kterým lze specifikovat, že se jednotlivé prvky matice mají lišit svojí hodnotou. To ovšem neplatí pro hodnotu NaN, která se v matici může vyskytnou vícekrát, protože platí NaN != NaN.

Tento jednoduchý demonstrační příklad vygeneruje trojrozměrné matice jejichž prvky opět obsahují i „speciální“ hodnoty:

[[[-1.100e+00  0.000e+00       -inf  1.192e-07]
  [       nan -3.333e-01        nan        nan]
  [ 1.500e+00  1.100e+00        nan        inf]]
 
 [[-1.001e-05  5.000e-01        nan -1.500e+00]
  [-1.192e-07 -2.000e+00 -1.900e+00 -5.000e-01]
  [ 2.000e+00        nan  3.333e-01        nan]]]
 
[[[       nan -1.000e+00  1.192e-07  1.900e+00]
  [       nan  1.001e-05        inf -0.000e+00]
  [       nan -5.000e-01 -3.333e-01        nan]]
 
 [[-1.500e+00       -inf        nan  1.500e+00]
  [-1.192e-07        nan  2.000e+00        nan]
  [       nan        nan        nan        nan]]]
 
[[[-0.000e+00        nan        inf        nan]
  [      -inf        nan        nan        nan]
  [ 1.900e+00  5.000e-01        nan        nan]]
 
 [[       nan        nan -5.000e-01  1.100e+00]
  [       nan  1.000e+00 -3.333e-01 -1.001e-05]
  [       nan        nan        nan  1.500e+00]]]
 
[[[-0.000e+00  1.500e+00 -1.192e-07        nan]
  [ 1.100e+00  1.900e+00        inf        nan]
  [       nan        nan  5.000e-01        nan]]
 
 [[      -inf        nan  2.000e+00 -1.001e-05]
  [       nan        nan        nan  1.192e-07]
  [-3.333e-01        nan -2.000e+00 -5.000e-01]]]
 
[[[-1.900e+00  0.000e+00        inf  1.100e+00]
  [ 3.333e-01 -5.000e-01        nan -1.100e+00]
  [       nan -1.192e-07  1.192e-07        nan]]
 
 [[       nan -2.000e+00        nan  2.000e+00]
  [-1.001e-05        nan       -inf  1.900e+00]
  [       nan  1.001e-05 -3.333e-01        nan]]]
 
[[[       nan        inf  1.100e+00  0.000e+00]
  [-1.500e+00        nan       -inf -1.192e-07]
  [ 2.000e+00        nan -1.000e+00        nan]]
 
 [[       nan        nan        nan  1.001e-05]
  [       nan -3.333e-01  1.192e-07  3.333e-01]
  [       nan        nan -1.001e-05        nan]]]
 
[[[       inf  3.333e-01  1.192e-07        nan]
  [-3.333e-01  2.000e+00 -0.000e+00        nan]
  [      -inf        nan -1.001e-05 -5.000e-01]]
 
 [[       nan  1.500e+00        nan        nan]
  [       nan  5.000e-01  1.001e-05        nan]
  [       nan -1.500e+00  1.100e+00        nan]]]
 
[[[   -inf  0.5     0.         inf]
  [-1.         nan  1.      2.    ]
  [-0.3333     nan -2.     -1.9   ]]
 
 [[ 1.1        nan  1.9        nan]
  [    nan -1.5        nan     nan]
  [ 1.5        nan     nan  0.3333]]]
 
[[[      -inf  3.333e-01  1.001e-05  1.192e-07]
  [-1.000e+00        inf  0.000e+00  1.500e+00]
  [-1.001e-05        nan -1.192e-07        nan]]
 
 [[       nan -2.000e+00        nan        nan]
  [-1.900e+00  5.000e-01        nan -3.333e-01]
  [       nan        nan  1.900e+00  1.000e+00]]]
 
[[[     nan -1.0e-05 -0.0e+00 -1.2e-07]
  [     nan      nan      nan -1.0e+00]
  [ 1.9e+00  1.5e+00     -inf      inf]]
 
 [[     nan      nan -5.0e-01      nan]
  [ 1.0e+00  1.1e+00      nan      nan]
  [     nan  1.2e-07      nan  2.0e+00]]]

16. Bližší specifikace hodnot prvků v generovaných polích

V mnoha případech je nutné blíže specifikovat hodnoty prvků v pseudonáhodně generovaných polích. I to je možné, i když s určitými omezeními. Podívejme se na následující demonstrační příklad, v němž jsou generovány trojrozměrné matice s prvky typu celé číslo, ovšem hodnoty prvků jsou navíc omezeny tím, že musí být v rámci jedné matice unikátní a současně musí být v rozsahu 0 až 100:

import numpy as np
from hypothesis.strategies import integers
from hypothesis.extra.numpy import arrays
 
g = arrays(np.int32, (2,3,4), elements=integers(0, 100), unique=True)
 
for _ in range(10):
    print(g.example())
    print()

S výsledky:

[[[ 88  60  59  99]
  [ 78   3  83 100]
  [ 26  98  95   8]]
 
 [[ 74  47  66  48]
  [ 73  42  70  31]
  [ 14  75  62  24]]]
 
[[[27 90 54 48]
  [ 0  3 36 89]
  [37 68 60 19]]
 
 [[31 75 16 97]
  [10 29 17 70]
  [84 82 43 85]]]
 
[[[38 89 81 27]
  [69 74 87 46]
  [95  4 67 23]]
 
 [[99 83 35 11]
  [ 3 10 54 58]
  [36 20 75 50]]]
 
[[[52 74  5 71]
  [89 15 18 40]
  [ 0 86 45 97]]
 
 [[39 69 96 35]
  [25  8 66 50]
  [43 51 26 32]]]
 
   ...
   ...
   ...
 
 [[46 39 90 31]
  [22  4 69 57]
  [49 81 68 91]]]

17. Závěr

Ve dvojici článků jsme si ukázali některé základní způsoby použití knihovny Hypothesis pro vylepšení pokrytí stavového prostoru bloků (funkcí, metod, objektů) jednotkovými testy. Tento nástroj prozatím není dokonalý a některé jeho vlastnosti pravděpodobně příliš neoceníte – například je problemativké (nikoli však nemožné) pracovat s rekurzivními datovými strukturami či generovat obecnější struktury na základě jejich schématu. K tomuto účelu je podle mého názoru vhodnější použít specializovanější knihovny, z nichž některé si popíšeme v navazujících částech tohoto seriálu.

MIF obecny

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ě několik desítek 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 factorial1/factorial.py funkce pro rekurzivní výpočet faktoriálu https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/factorial1/factorial.py
2 factorial1/factorial_test.py neúplné testy používající Hypothesis https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/factorial1/factorial_tes­t.py
       
3 factorial2/factorial.py funkce pro rekurzivní výpočet faktoriálu https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/factorial2/factorial.py
4 factorial2/factorial_test.py vylepšené testy používající Hypothesis https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/factorial2/factorial_tes­t.py
       
5 factorial3/factorial.py funkce pro rekurzivní výpočet faktoriálu https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/factorial3/factorial.py
6 factorial3/factorial_test.py testy používající Hypothesis založené na metodě filter https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/factorial3/factorial_tes­t.py
       
7 factorial4/factorial.py funkce pro rekurzivní výpočet faktoriálu https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/factorial4/factorial.py
8 factorial4/factorial_test.py testy používající Hypothesis založené na orákulu https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/factorial4/factorial_tes­t.py
       
9 primes1/is_prime.py test (predikát) na prvočíslo https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes1/is_prime.py
10 primes1/is_prime_test.py otestování funkce is_prime pro sudé vstupy získané filtrací https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes1/is_prime_test­.py
       
11 primes2/is_prime.py test (predikát) na prvočíslo https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes2/is_prime.py
12 primes2/is_prime_test.py otestování funkce is_prime pro sudé vstupy získané výpočtem v map https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes2/is_prime_test­.py
       
13 primes3/is_prime.py test (predikát) na prvočíslo https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes3/is_prime.py
14 primes3/is_prime_test.py otestování funkce is_prime s využitím Eulerova polynomu https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes3/is_prime_test­.py
       
15 primes4/is_prime.py test (predikát) na prvočíslo https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes4/is_prime.py
16 primes4/is_prime_test.py otestování funkce is_prime generátoru a strategie builds https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes4/is_prime_test­.py
       
17 primes5/is_prime.py test (predikát) na prvočíslo https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes5/is_prime.py
18 primes5/is_prime_test.py testy používající Hypothesis založené na orákulu https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes5/is_prime_test­.py
       
19 primes6/is_prime.py test (predikát) na prvočíslo https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes6/is_prime.py
20 primes6/is_prime_test.py testy používající Hypothesis založené na orákulu https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes6/is_prime_test­.py
       
21 primes7/is_prime.py test (predikát) na prvočíslo https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes7/is_prime.py
22 primes7/is_prime_test.py kombinace předchozích testů https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/primes7/is_prime_test­.py
       
23 from_regex1.py knihovna Hypothesis a regulární výrazy: generování kódů barev https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/from_regex1.py
24 from_regex2.py knihovna Hypothesis a regulární výrazy: generování kódů barev https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/from_regex2.py
25 from_regex3.py generování e-mailových adres https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/from_regex3.py
26 from_regex4.py generování e-mailových adres https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/from_regex4.py
       
27 numpy1.py generování dat (polí) pro Numpy nástrojem Hypothesis https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/numpy1.py
28 numpy2.py generování dat (polí) pro Numpy nástrojem Hypothesis https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/numpy2.py
29 numpy3.py generování dat (polí) pro Numpy nástrojem Hypothesis https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/numpy3.py
30 numpy4.py generování dat (polí) pro Numpy nástrojem Hypothesis https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/numpy4.py
31 numpy5.py generování dat (polí) pro Numpy nástrojem Hypothesis https://github.com/tisnik/testing-in-python/tree/master/hypothe­sis/numpy5.py

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. Použití Pythonu pro tvorbu testů: od jednotkových testů až po testy UI
    https://www.root.cz/clanky/pouziti-pythonu-pro-tvorbu-testu-od-jednotkovych-testu-az-po-testy-ui/
  2. Použití Pythonu pro tvorbu testů: použití třídy Mock z knihovny unittest.mock
    https://www.root.cz/clanky/pouziti-pythonu-pro-tvorbu-testu-pouziti-tridy-mock-z-knihovny-unittest-mock/
  3. Použití nástroje pytest pro tvorbu jednotkových testů a benchmarků
    https://www.root.cz/clanky/pouziti-nastroje-pytest-pro-tvorbu-jednotkovych-testu-a-benchmarku/
  4. Nástroj pytest a jednotkové testy: fixtures, výjimky, parametrizace testů
    https://www.root.cz/clanky/nastroj-pytest-a-jednotkove-testy-fixtures-vyjimky-parametrizace-testu/
  5. Nástroj pytest a jednotkové testy: životní cyklus testů, užitečné tipy a triky
    https://www.root.cz/clanky/nastroj-pytest-a-jednotkove-testy-zivotni-cyklus-testu-uzitecne-tipy-a-triky/
  6. Struktura projektů s jednotkovými testy, využití Travis CI
    https://www.root.cz/clanky/struktura-projektu-s-jednotkovymi-testy-vyuziti-travis-ci/
  7. Omezení stavového prostoru testovaných funkcí a metod
    https://www.root.cz/clanky/omezeni-stavoveho-prostoru-testovanych-funkci-a-metod/
  8. Testování aplikací s využitím nástroje Hypothesis
    https://www.root.cz/clanky/testovani-aplikaci-s-vyuzitim-nastroje-hypothesis/
  9. 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/
  10. 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/
  11. 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/
  12. 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/
  13. Validace datových struktur v Pythonu (2. část)
    https://www.root.cz/clanky/validace-datovych-struktur-v-pythonu-2-cast/
  14. Validace datových struktur v Pythonu (dokončení)
    https://www.root.cz/clanky/validace-datovych-struktur-v-pythonu-dokonceni/
  15. Univerzální testovací nástroj Robot Framework
    https://www.root.cz/clanky/univerzalni-testovaci-nastroj-robot-framework/
  16. Univerzální testovací nástroj Robot Framework a BDD testy
    https://www.root.cz/clanky/univerzalni-testovaci-nastroj-robot-framework-a-bdd-testy/
  17. Úvod do problematiky fuzzingu a fuzz testování
    https://www.root.cz/clanky/uvod-do-problematiky-fuzzingu-a-fuzz-testovani/
  18. Ú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/
  19. 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/
  20. 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/
  21. Testování aplikací naprogramovaných v jazyce Go
    https://www.root.cz/clanky/testovani-aplikaci-naprogramovanych-v-jazyce-go/
  22. 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/
  23. 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/
  24. 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/
  25. 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/
  26. 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/
  27. 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/
  28. 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/
  29. 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. Prime formulas and polynomial functions
    https://en.wikipedia.org/wi­ki/Formula_for_primes#Pri­me_formulas_and_polynomial_fun­ctions
  2. Prime-Generating Polynomial
    https://mathworld.wolfram.com/Prime-GeneratingPolynomial.html
  3. Hoare logic
    https://en.wikipedia.org/wi­ki/Hoare_logic
  4. Goto Fail, Heartbleed, and Unit Testing Culture
    https://martinfowler.com/ar­ticles/testing-culture.html
  5. PEP-484
    https://www.python.org/dev/peps/pep-0484/
  6. In-depth: Functional programming in C++
    https://www.gamasutra.com/vi­ew/news/169296/Indepth_Fun­ctional_programming_in_C.php
  7. mypy
    http://www.mypy-lang.org/
  8. Welcome to Mypy documentation!
    https://mypy.readthedocs.i­o/en/latest/index.html
  9. mypy na GitHubu
    https://github.com/python/mypy
  10. mypy 0.770 na PyPi
    https://pypi.org/project/mypy/
  11. Extensions for mypy (separated out from mypy/extensions)
    https://github.com/python/my­py_extensions
  12. The Mypy Blog
    https://mypy-lang.blogspot.com/2020/03/mypy-0770-released.html
  13. Our journey to type checking 4 million lines of Python
    https://dropbox.tech/application/our-journey-to-type-checking-4-million-lines-of-python
  14. Type-Checking Python Programs With Type Hints and mypy
    https://www.youtube.com/wat­ch?v=2×WhaALHTvU
  15. Refactoring to Immutability – Kevlin Henney
    https://www.youtube.com/wat­ch?v=APUCMSPiNh4
  16. Bernat Gabor – Type hinting (and mypy) – PyCon 2019
    https://www.youtube.com/wat­ch?v=hTrjTAPnA_k
  17. Stanford Seminar – Optional Static Typing for Python
    https://www.youtube.com/wat­ch?v=GiZKuyLKvAA
  18. mypy Getting to Four Million Lines of Typed Python – Michael Sullivan
    https://www.youtube.com/wat­ch?v=FT_WHV4-QcU
  19. Shebang
    https://en.wikipedia.org/wi­ki/Shebang_(Unix)
  20. pytest 5.4.2 na PyPi
    https://pypi.org/project/pytest/
  21. Hillel Wayne – Beyond Unit Tests: Taking Your Testing to the Next Level – PyCon 2018
    https://www.youtube.com/wat­ch?v=MYucYon2-lk
  22. Awesome Python – testing
    https://github.com/vinta/awesome-python#testing
  23. pytest Plugins Compatibility
    http://plugincompat.herokuapp.com/
  24. Selenium (pro Python)
    https://pypi.org/project/selenium/
  25. Getting Started With Testing in Python
    https://realpython.com/python-testing/
  26. unittest.mock — mock object library
    https://docs.python.org/3­.5/library/unittest.mock.html
  27. mock 2.0.0
    https://pypi.python.org/pypi/mock
  28. An Introduction to Mocking in Python
    https://www.toptal.com/python/an-introduction-to-mocking-in-python
  29. Mock – Mocking and Testing Library
    http://mock.readthedocs.io/en/stable/
  30. Python Mocking 101: Fake It Before You Make It
    https://blog.fugue.co/2016–02–11-python-mocking-101.html
  31. Nauč se Python! – Testování
    http://naucse.python.cz/les­sons/intro/testing/
  32. Flexmock (dokumentace)
    https://flexmock.readthedoc­s.io/en/latest/
  33. Test Fixture (Wikipedia)
    https://en.wikipedia.org/wi­ki/Test_fixture
  34. Mock object (Wikipedia)
    https://en.wikipedia.org/wi­ki/Mock_object
  35. Extrémní programování
    https://cs.wikipedia.org/wi­ki/Extr%C3%A9mn%C3%AD_pro­gramov%C3%A1n%C3%AD
  36. Programování řízené testy
    https://cs.wikipedia.org/wi­ki/Programov%C3%A1n%C3%AD_%C5%99%­C3%ADzen%C3%A9_testy
  37. Pip (dokumentace)
    https://pip.pypa.io/en/stable/
  38. Tox
    https://tox.readthedocs.io/en/latest/
  39. pytest: helps you write better programs
    https://docs.pytest.org/en/latest/
  40. doctest — Test interactive Python examples
    https://docs.python.org/dev/li­brary/doctest.html#module-doctest
  41. unittest — Unit testing framework
    https://docs.python.org/dev/li­brary/unittest.html
  42. Python namespaces
    https://bytebaker.com/2008/07/30/pyt­hon-namespaces/
  43. Namespaces and Scopes
    https://www.python-course.eu/namespaces.php
  44. Stránka projektu Robot Framework
    https://robotframework.org/
  45. GitHub repositář Robot Frameworku
    https://github.com/robotfra­mework/robotframework
  46. Robot Framework (Wikipedia)
    https://en.wikipedia.org/wi­ki/Robot_Framework
  47. Tutoriál Robot Frameworku
    http://www.robotframeworktu­torial.com/
  48. Robot Framework Documentation
    https://robotframework.or­g/robotframework/
  49. Robot Framework Introduction
    https://blog.testproject.i­o/2016/11/22/robot-framework-introduction/
  50. robotframework 3.1.2 na PyPi
    https://pypi.org/project/ro­botframework/
  51. Robot Framework demo (GitHub)
    https://github.com/robotfra­mework/RobotDemo
  52. Robot Framework web testing demo using SeleniumLibrary
    https://github.com/robotfra­mework/WebDemo
  53. Robot Framework for Mobile Test Automation Demo
    https://www.youtube.com/wat­ch?v=06LsU08slP8
  54. Gherkin
    https://cucumber.io/docs/gherkin/
  55. Selenium
    https://selenium.dev/
  56. SeleniumLibrary
    https://robotframework.org/
  57. The Practical Test Pyramid
    https://martinfowler.com/ar­ticles/practical-test-pyramid.html
  58. Acceptance Tests and the Testing Pyramid
    http://www.blog.acceptance­testdrivendevelopment.com/ac­ceptance-tests-and-the-testing-pyramid/
  59. Tab-separated values
    https://en.wikipedia.org/wiki/Tab-separated_values
  60. A quick guide about Python implementations
    https://blog.rmotr.com/a-quick-guide-about-python-implementations-aa224109f321
  61. radamsa
    https://gitlab.com/akihe/radamsa
  62. Fuzzing (Wikipedia)
    https://en.wikipedia.org/wiki/Fuzzing
  63. american fuzzy lop
    http://lcamtuf.coredump.cx/afl/
  64. Fuzzing: the new unit testing
    https://go-talks.appspot.com/github.com/dvyukov/go-fuzz/slides/fuzzing.slide#1
  65. Corpus for github.com/dvyukov/go-fuzz examples
    https://github.com/dvyukov/go-fuzz-corpus
  66. AFL – QuickStartGuide.txt
    https://github.com/google/AF­L/blob/master/docs/QuickStar­tGuide.txt
  67. Introduction to Fuzzing in Python with AFL
    https://alexgaynor.net/2015/a­pr/13/introduction-to-fuzzing-in-python-with-afl/
  68. Writing a Simple Fuzzer in Python
    https://jmcph4.github.io/2018/01/19/wri­ting-a-simple-fuzzer-in-python/
  69. How to Fuzz Go Code with go-fuzz (Continuously)
    https://fuzzit.dev/2019/10/02/how-to-fuzz-go-code-with-go-fuzz-continuously/
  70. Golang Fuzzing: A go-fuzz Tutorial and Example
    http://networkbit.ch/golang-fuzzing/
  71. Fuzzing Python Modules
    https://stackoverflow.com/qu­estions/20749026/fuzzing-python-modules
  72. 0×3 Python Tutorial: Fuzzer
    http://www.primalsecurity.net/0×3-python-tutorial-fuzzer/
  73. fuzzing na PyPi
    https://pypi.org/project/fuzzing/
  74. Fuzzing 0.3.2 documentation
    https://fuzzing.readthedoc­s.io/en/latest/
  75. Randomized testing for Go
    https://github.com/dvyukov/go-fuzz
  76. HTTP/2 fuzzer written in Golang
    https://github.com/c0nrad/http2fuzz
  77. 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
  78. Continuous Fuzzing Made Simple
    https://fuzzit.dev/
  79. Halt and Catch Fire
    https://en.wikipedia.org/wi­ki/Halt_and_Catch_Fire#In­tel_x86
  80. Random testing
    https://en.wikipedia.org/wi­ki/Random_testing
  81. Monkey testing
    https://en.wikipedia.org/wi­ki/Monkey_testing
  82. 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
  83. libFuzzer – a library for coverage-guided fuzz testing
    https://llvm.org/docs/LibFuzzer.html
  84. fuzzy-swagger na PyPi
    https://pypi.org/project/fuzzy-swagger/
  85. fuzzy-swagger na GitHubu
    https://github.com/namuan/fuzzy-swagger
  86. Fuzz testing tools for Python
    https://wiki.python.org/mo­in/PythonTestingToolsTaxo­nomy#Fuzz_Testing_Tools
  87. A curated list of awesome Go frameworks, libraries and software
    https://github.com/avelino/awesome-go
  88. gofuzz: a library for populating go objects with random values
    https://github.com/google/gofuzz
  89. tavor: A generic fuzzing and delta-debugging framework
    https://github.com/zimmski/tavor
  90. hypothesis na GitHubu
    https://github.com/Hypothe­sisWorks/hypothesis
  91. Hypothesis: Test faster, fix more
    https://hypothesis.works/
  92. Hypothesis
    https://hypothesis.works/ar­ticles/intro/
  93. What is Hypothesis?
    https://hypothesis.works/articles/what-is-hypothesis/
  94. What is Property Based Testing?
    https://hypothesis.works/articles/what-is-property-based-testing/
  95. Databáze CVE
    https://www.cvedetails.com/
  96. Fuzz test Python modules with libFuzzer
    https://github.com/eerimoq/pyfuzzer
  97. Taof – The art of fuzzing
    https://sourceforge.net/pro­jects/taof/
  98. JQF + Zest: Coverage-guided semantic fuzzing for Java
    https://github.com/rohanpadhye/jqf
  99. http2fuzz
    https://github.com/c0nrad/http2fuzz
  100. Demystifying hypothesis testing with simple Python examples
    https://towardsdatascience­.com/demystifying-hypothesis-testing-with-simple-python-examples-4997ad3c5294
  101. Testování
    http://voho.eu/wiki/testovani/
  102. Unit testing (Wikipedia.en)
    https://en.wikipedia.org/wi­ki/Unit_testing
  103. Unit testing (Wikipedia.cz)
    https://cs.wikipedia.org/wi­ki/Unit_testing
  104. Unit Test vs Integration Test
    https://www.youtube.com/wat­ch?v=0GypdsJulKE
  105. TestDouble
    https://martinfowler.com/bli­ki/TestDouble.html
  106. Test Double
    http://xunitpatterns.com/Tes­t%20Double.html
  107. Test-driven development (Wikipedia)
    https://en.wikipedia.org/wiki/Test-driven_development
  108. Acceptance test–driven development
    https://en.wikipedia.org/wi­ki/Acceptance_test%E2%80%93dri­ven_development
  109. Gauge
    https://gauge.org/
  110. Gauge (software)
    https://en.wikipedia.org/wi­ki/Gauge_(software)
  111. PYPL PopularitY of Programming Language
    https://pypl.github.io/PYPL.html
  112. 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
  113. Články a zprávičky věnující se Pythonu
    https://www.root.cz/n/python/
  114. PythonTestingToolsTaxonomy
    https://wiki.python.org/mo­in/PythonTestingToolsTaxo­nomy
  115. Top 6 BEST Python Testing Frameworks [Updated 2020 List]
    https://www.softwaretestin­ghelp.com/python-testing-frameworks/
  116. pytest-print 0.1.3
    https://pypi.org/project/pytest-print/
  117. pytest fixtures: explicit, modular, scalable
    https://docs.pytest.org/en/la­test/fixture.html
  118. PyTest Tutorial: What is, Install, Fixture, Assertions
    https://www.guru99.com/pytest-tutorial.html
  119. Pytest – Fixtures
    https://www.tutorialspoin­t.com/pytest/pytest_fixtu­res.htm
  120. Marking test functions with attributes
    https://docs.pytest.org/en/la­test/mark.html
  121. pytest-print
    https://pytest-print.readthedocs.io/en/latest/
  122. Continuous integration
    https://en.wikipedia.org/wi­ki/Continuous_integration
  123. Travis CI
    https://travis-ci.org/
  124. Mutation testing
    https://en.wikipedia.org/wi­ki/Mutation_testing
  125. Články o Hypothesis
    https://news.ycombinator.com/from?si­te=hypothesis.works
  126. Testovací případ
    https://cs.wikipedia.org/wi­ki/Testovac%C3%AD_p%C5%99%C3%AD­pad
  127. Most testing is ineffective
    https://hypothesis.works/