Vytvořte si AI tutoriál na míru! Vyzkoušejte generátor tutoriálů a ušetřete čas.

AI Tutoriál

Jak testovat aplikace v pythonu

Proč testovat software?

Testování softwaru je důležitým krokem v procesu vývoje softwaru. Zajišťuje, že výsledný produkt funguje podle očekávání, je stabilní a bez chyb. Testování nám umožňuje:
  • Zjistit a opravit chyby (tzv.
    bugy
    ) v kódu dříve, než je software nasazen do produkčního prostředí. To minimalizuje riziko selhání a snižuje náklady na opravy pozdějších chyb.
  • Zlepšit kvalitu kódu tím, že nám usnadní včasnou detekci a nápravu chyb v logice programu a v designu softwaru. Dobře napsané testy nám pomohou odhalit i skryté problémy.
  • Zvýšit důvěru v software. Víme, že náš software funguje podle očekávání, ať už se změní požadavky, nebo se software upraví. Díky testům se stáváme méně závislí na manuálním ověřování funkčnosti.
  • Urychlit vývoj. Testování dovoluje nám rychleji a efektivněji měnit a rozvíjet fungující kód a zároveň se ujistit, že tyto změny nezpůsobují problémy. To je důležité pro rychlý vývojový cyklus.
  • Snadno ověřovat změny. Testování nám umožňuje snadno ověřit, zda se změnami v kódu neztratily stávající funkce. To je důležité pro udržení stability softwaru během vývoje.
V závěru se dá říci, že testování je nezbytnou součástí moderního vývoje softwaru. Je důležité si zapamatovat, že testování softwaru není jen o hledání chyb, ale o zajištění kvality a stability softwaru. Bez testování bychom riskovali zbytečné náklady, ztráty času a potenciální selhání softwaru.

Typy testů v Pythonu

V Pythonu existuje několik typů testů, které slouží k ověření různých aspektů vašeho softwaru. Tyto typy se liší svým zaměřením a úrovní detailu testování.
  • Unit testy
    - zaměřují se na testování jednotlivých funkcí a metod. Jsou nejmenšími jednotkami testování a slouží k ověření, zda funkce funguje tak, jak má.
  • Integrační testy
    - ověřují, zda jednotlivé komponenty vašeho softwaru správně spolupracují. Zahrnují testování interakcí mezi funkcemi, moduly a třídami.
  • Funkční testy
    - testují systém jako celek a ověřují, zda systém plní svou celkovou funkčnost. Jsou důležité k ověření, zda systém funguje správně z pohledu uživatele.
  • Regresní testy
    - slouží k ověření, zda změny v kódu nezpůsobily neočekávané problémy v jiných částech systému. Jsou důležité pro udržení kvality softwaru.
  • Uživatel by se mohl zamyslet nad tím, jaký typ testu je pro danou situaci nejvhodnější. Doporučuji se zamyslet nad cílem testu a úrovní detailu, který je potřeba.
  • Výhody testování

    Testování software je v Pythonu, stejně jako v jakémkoli jiné programovacím jazyce, **nezbytné** pro tvorbu kvalitních a spolehlivých aplikací. Prináší mnoho výhod, které se projevuí jak béhem vývoje, tak i po nasazení aplikace.
    Zde je nêkolik hlavních výhod testování:
    • Zajišťuje kvalitu a spolehlivost: Testy výrazně sníží pravděpodobnost chybového chování softwaru a pomáhají zachovat jeho správnou funkčnost během celého vývojového cyklu.
    • Snižuje rizika: Vývojové chyby odhalené v rané fázi vývoje jsou méně nákladné na opravu, než chyby objevené po nasazení aplikace.
    • Zjednodušuje údržbu a vývoj: Dobře napsané testy slouží jako dokumentace chování softwaru a zaručují, že po zmênách kódu se zachová správná funkčnost.
    • Podporuje refaktoring: Testování umožňuje bezpečněji refaktorovat kód a výkonněji optimalizovat jeho strukturu.
    • Zlepšuje komunikaoci v týmu: Testy definují očekávané chování softwaru a slouží jako srozumitelná dokumentace pro údržbářé, tým pro vývoj i pro údržbu softwaru.
  • Je dúležité si uvědomit, že testování samo o sobê nezajišťuje 100% správné chování softwaru. Existuje mnoho druhù chybového chování, které se testy nedá detekovat - například chyby v logice nebo chybně implementované obchodní pravidla.
  • Modul unittest

    Modul
    unittest
    je součástí standardní knihovny Pythonu a je základním nástrojem pro testování vašeho kódu. Poskytuje základní strukturu a funkce pro definování a spouštění testů.

    Základní struktura testů

    Testy v
    unittest
    se zapisují do tříd, které dědí od třídy
    TestCase
    . Každý test je definován jako metoda v této třídě. Tyto metody musí začínat prefixem
    test_
    .
    Ukázka struktury testu:
    import unittest
    
    def soucet(a, b):
        return a + b
    
    class TestSoucet(unittest.TestCase):
        def test_soucet_kladnych(self):
            self.assertEqual(soucet(2, 3), 5)
    
        def test_soucet_zapornych(self):
            self.assertEqual(soucet(-2, -3), -5)
    
        def test_soucet_kombinace(self):
            self.assertEqual(soucet(2, -3), -1)
    
    if __name__ == '__main__':
        unittest.main()
    
  • Uživatel by mohl mít problémy s pochopením, jaký je účel třídy
    TestCase
    a co dědí od třídy
    unittest
    .
  • Uživatel by mohl mít problémy s definováním názvů testů tak, aby začínali prefixem
    test_
    .
  • Třída TestCase

    Třída
    TestCase
    poskytuje různé metody pro porovnávání výsledků testů a pro generování výjimek v případě, že test selže. Mezi nejdůležitější metody patří:
    • assertEqual(a, b): Ověří, zda se hodnoty
      a
      a
      b
      rovnají.
    • assertNotEqual(a, b): Ověří, zda se hodnoty
      a
      a
      b
      nerovnají.
    • assertTrue(x): Ověří, zda je hodnota
      x
      pravdivá (True).
    • assertFalse(x): Ověří, zda je hodnota
      x
      nepravdivá (False).
    • assertIsNone(x): Ověří, zda je hodnota
      x
      typu
      None
      .
    • assertIsNotNone(x): Ověří, zda hodnota
      x
      není typu
      None
      .
    • assertRaises(ExceptionType, callable, *args, **kwargs): Ověří, zda daná funkce (callable) vyvolá specifickou výjimku (ExceptionType).
  • Uživatel by mohl mít problémy s pochopením, co znamená
    callable
    a jak se používá v metodě
    assertRaises
    .
  • Metody pro testování

    Kromě metod pro porovnávání a ověřování výsledků poskytuje
    unittest
    i další metody pro testování:
    • setUp(): Tato metoda se spustí před každým testem v testovací třídě. Je užitečná pro inicializaci proměnných a nastavení prostředí pro testy.
    • tearDown(): Tato metoda se spustí po každém testu v testovací třídě. Je užitečná pro uvolnění prostředků a pro čištění stavu po provedení testu.
    • skipTest(reason): Tato metoda zruší provedení daného testu. Důvodem pro zrušení může být, že test je momentálně nepoužitelný nebo že by jeho provedení mohlo způsobit problémy. V parametru
      reason
      uvádíme text s vysvětlením.
  • Uživatel by mohl mít problémy s pochopením, kdy a jak používat metody
    setUp
    a
    tearDown
    .
  • Uživatel by mohl mít problémy s pochopením, jak používat metodu
    skipTest
    a jak uvádět důvod zrušení testu.
  • Spouštění testů

    Testovací skripty s testy v modulu
    unittest
    se spouští pomocí funkce
    unittest.main()
    . Pokud je skript spuštěn přímo, funkce
    unittest.main()
    automaticky najde a spustí všechny testy v tomto skriptu. Jinak se testy spouští pomocí importu modulu
    unittest
    a volání funkce:
    import unittest
    unittest.main()
    
    Funkce
    unittest.main()
    vrací výsledek testování (zda všechny testy proběhly úspěšně).
  • Uživatel by mohl mít problémy s pochopením, jak a kdy spustit testy.
  • PyTest

    PyTest je populární a mocný framework pro testování v Pythonu. Nabízí flexibilní a uživatelsky přívětivou syntax pro psaní testů a širokou škálu funkcí pro pokročilé testování.

    Instalace a konfigurace

    PyTest je dostupný jako balíček, který si můžeme nainstalovat pomocí nástroje pip.
    pip install pytest
    Po instalaci můžeme testovací soubory jednoduše spustit příkazem:
    pytest
    PyTest automaticky detekuje testovací soubory a třídy podle konvencí pojmenování (souborům s příponou `_test.py` a třídám s příponou `Test`) a spouští testy.
  • Pokud PyTest nenajdete, ujistěte se, že jste ho nainstalovali do vašeho virtuálního prostředí (pokud používáte).
  • Ujistěte se, že máte nainstalovanou nejnovější verzi nástroje `pip`.
  • Základní syntaxe testů

    PyTest používá funkce pro definici testů. Funkce, které testují kód, se poznají podle předpony `test_`. Níže ukazujeme jednoduchý příklad testu.
    def test_add(): assert 1 + 1 == 2
    V tomto příkladu funkce `test_add()` ověřuje, že součet čísla 1 a 1 se rovná 2. K tomu používá funkci `assert` s podmínkou, která má být splněna. Pokud je podmínka splněna, test proběhne úspěšně. Pokud není splněna, test selže a zobrazí chybovou zprávu.

    Pokročilé funkce PyTest

    PyTest nabízí širokou škálu funkcí pro pokročilé testování, které nám umožňují psát komplexní a organizované testy. Mezi nejpoužívanější funkce patří:
    • Parametrické testy (Parametrization) - s touto funkcí můžeme spustit stejný test s různými vstupními daty a očekávanými výsledky. Tím se snižuje množství kódu a zvyšuje se přehlednost testů.
    • Fixtures - Pomocí fixtures můžeme vytvářet a sdílet data pro testy. To je užitečné pro přípravu testů, například vytvoření testovací databáze nebo inicializaci objektu.
    • Mocking - Pomocí mockingu můžeme nahradit závislosti na jiných funkcích nebo modulech a izolovat funkčnost, kterou chceme testovat.
    • Pluginy - PyTest má rozsáhlou ekosystému pluginů, které rozšiřují jeho funkce a usnadňují testování specifických případů použití.
    Pro podrobnější informace o pokročilých funkcích PyTest se podívejte do oficiální dokumentace PyTest: https://docs.pytest.org/en/latest/.

    Unit testy

    Unit testy, jak již název napovídá, se zaměřují na testování jednotlivých a izolovaných částí kódu. Tyto části se označují jako jednotky a typicky se jedná o funkce nebo metody. Cílem unit testů je ověřit, zda daná funkce pracuje správně a podle očekávání, bez ohledu na ostatní části kódu.

    Testování jednotlivých funkcí

    Unit testy se obvykle skládají z několika kroků:
    • Příprava vstupních dat: Nejdříve je potřeba připravit vstupní data, která se budou předávat do testované funkce.
    • Spuštění testované funkce: Poté se spustí testovaná funkce s připravenými vstupními daty.
    • Ověření výstupu: Nakonec se porovná výstup testované funkce s očekávaným výsledkem. Pokud se výstup shoduje s očekáváním, test prošel, v opačném případě se jedná o chybu (bug) v kódu.
  • Uživatel by se mohl zamyslet nad tím, jaká data by měl pro testy použít. Je důležité zahrnout různé typy dat, včetně hranicních a neplatných dat, aby se ověřilo, že funkce funguje správně za různých podmínek.
  • Výhody a nevýhody

    Unit testy mají mnoho výhod, ale i některé nevýhody:
    • Výhody:
      • Snadná identifikace chyb: Unit testy umožňují snadno identifikovat chyby v izolovaných částech kódu.
      • Rychlá provádění: Unit testy se provádí velmi rychle, protože testují pouze malé části kódu.
      • Snadná údržba: Unit testy se snadno udržují, protože se po změnách v kódu musí testovat pouze dotčené funkce.
      • Zlepšují kvalitu kódu: Unit testy podporují psaní čistého a testovatelného kódu.
    • Nevýhody:
      • Nezachycují všechny chyby: Unit testy nezachycují všechny typy chyb, například chyby v interakci mezi komponentami.
      • Může být časově náročné: Napsat kompletní sadu unit testů pro rozsáhlý projekt může být časově náročné.

    Integrační testy

    Integrační testy ověřují, zda jednotlivé komponenty vašeho softwaru správně spolupracují. Zahrnují testování interakcí mezi funkcemi, moduly a třídami. Integrační testy se zaměřují na to, zda komponenty software fungují správně v kombinaci s ostatními, i když jednotlivě fungují bezchybně.
    • Testování interakce mezi komponentami
      - Ujistěte se, že různé části vašeho kódu fungují správně, když jsou propojeny. Například, pokud máte modul, který zpracovává data a modul, který je ukládá do databáze, integrační test by ověřil, zda data jsou správně převedena z jednoho modulu do druhého a zda jsou správně uložena v databázi.

    Výhody a nevýhody

    • Výhody
      • Odhalují problémy s integrací mezi komponentami, které by se mohly objevit až v pozdějších fázích vývoje.
      • Zajišťují, že systém jako celek funguje správně, i když se některé jeho komponenty změní.
      • Pomáhají vyhnout se chybám, které by se mohly objevit, kdyby se jednotlivé komponenty testovaly izolovaně.
    • Nevýhody
      • Integrační testy se mohou stát složitými, pokud má systém mnoho komponent.
      • Integrační testy můžou být náročné na údržbu, pokud se systém mění.
      • Integrační testy mohou být pomalé, protože je potřeba testovat mnoho komponent.
  • Uživatel si může klást otázku, jak implementovat integrační testy. Existuje několik nástrojů a technik pro integrační testování v Pythonu, včetně unittest, pytest a mockovacích knihoven.
  • Uživatel se může zamyslet nad tím, kolik integračních testů je potřeba. Existuje několik strategií pro určení rozsahu integračního testování, například testování všech hlavních integrací nebo testování jen kritických integrací.
  • Funkční testy

    Funkční testy se zaměřují na ověření celého softwarového systému z pohledu uživatele. Vycházejí z uživatelských scénářů a ověřují, zda systém plní své základní funkce a chová se tak, jak je očekáváno. Testy se nezaměřují na detaily implementace, ale na celkovou funkčnost systému a interakci s ním.

    Testování celého systému

    Funkční testy ověřují, zda systém správně reaguje na specifické vstupy a produkuje očekávané výstupy. Například můžeme testovat, zda se uživatel správně zaregistruje, zda se mu zobrazí správný obsah, zda se může přihlásit do systému, zda může procházet stránky a zadávat data.
  • Uživatel by se mohl zeptat, jak testovat komplexní scénáře, které zahrnují více částí systému. K tomu je vhodné využít nástroje, které podporují integraci s webovými prohlížeči a umožňují simulaci uživatelského chování, jako jsou Selenium nebo Cypress.
  • Výhody a nevýhody

    Funkční testy jsou důležité pro zajištění celkové funkčnosti a kvality systému z pohledu uživatele. Hlavní výhody funkčních testů zahrnují:
    • Ověřují komplexní chování systému a interakci s uživatelem.
    • Zlepšují kvalitu a stabilitu systému z pohledu uživatele.
    • Pomáhají odhalit problémy s uživatelským rozhraním.
    Na druhou stranu, funkční testy mohou být:
    • Zdlouhavé na psaní a údržbu.
    • Náročné na nastavení a spouštění.
    • Náchylnější k chybám, protože se testuje komplexní chování.

    Regresní testy

    Regresní testy představují důležitý typ testu, který se zaměřuje na zachování stávajících funkcí softwaru po provedení změn v kódu. Jde o to, aby se zabránilo vzniku nových chyb, nebo aby se zajistilo, že starší funkce stále pracují správně.
    • Kontrola zachování funkčnosti po změnách - Regresní testy se provádějí po každé změně kódu, aby bylo zajištěno, že nové změny nezpůsobily neočekávané problémy v jiných, již funkčních, částech softwaru. Tyto testy můžou zahrnovat opakované spuštění starších testů, které se již dříve ukázaly jako úspěšné.
    • Výhody a nevýhody
      • Výhody:
        • Zvýšení důvěry v software, že změny nevedou k rozbití starých funkcí.
        • Snižování rizika chyb a problémů v produkčním prostředí.
        • Usnadnění údržby a evoluce softwaru.
      • Nevýhody:
        • Možnost prodloužení času vývoje z důvodu dodatečného testování.
        • Náročnost na implementaci v případě, že je kód komplexní a obsahuje mnoho funkcí.
  • Uživatel by se mohl zmýlit v tom, kdy použít regresní testy. Je důležité si uvědomit, že se jedná o testy, které se běžně spouští po každé změně kódu, aby se zabránilo vzniku nových chyb.
  • Uživatel by se mohl potýkat s náročností implementace regresních testů v komplexních projektech. V takových situacích je vhodné využít nástroje pro automatizaci testování.
  • Testování jednoduché funkce

    Nyní se podíváme na praktické příklady, jak testovat jednoduché funkce v Pythonu. Budeme používat dva nejčastější frameworky pro testování: `unittest` a `PyTest`.

    Příklad s unittest

    Modul `unittest` je běžný framework pro testování v Pythonu, který je součástí standardní knihovny. Ukážeme si jednoduchý příklad testu pro funkci, která sečte dvě čísla.
    ```python def secti(a, b): """Funkce, která sečte dvě čísla. """ return a + b import unittest class TestSecti(unittest.TestCase): def test_secti_kladna_cisla(self): self.assertEqual(secti(2, 3), 5) def test_secti_zaporna_cisla(self): self.assertEqual(secti(-2, -3), -5) def test_secti_nula(self): self.assertEqual(secti(2, 0), 2) if __name__ == '__main__': unittest.main() ```
    V tomto kódu:
    • Definujeme funkci `secti` pro sčítání dvou čísel.
    • Importujeme modul `unittest` pro testování.
    • Vytvoříme třídu `TestSecti`, která dědí od `unittest.TestCase`.
    • Definujeme testovací metody:
      • `test_secti_kladna_cisla` testuje sčítání kladných čísel.
      • `test_secti_zaporna_cisla` testuje sčítání záporných čísel.
      • `test_secti_nula` testuje sčítání s nulou.
    • Používáme metodu `assertEqual` pro ověření, zda je výsledek sčítání správný.
    • Spouštíme testy pomocí `unittest.main()`.
  • Uživatel by se mohl zeptat, jak zjistit, zda testy proběhly úspěšně. Výstup z testů se zobrazí v konzole, kde se zobrazí informace o průběhu testů a zda testy proběhly bez chyb.
  • Po spuštění testů se zobrazí informace o průběhu testů a zda testy proběhly bez chyb.

    Příklad s PyTest

    PyTest je populární framework pro testování v Pythonu, který nabízí intuitivní a srozumitelný syntaxe pro definování testů. Ukážeme si, jak testovat funkci `secti` s použitím PyTestu.
    ```python def secti(a, b): """Funkce, která sečte dvě čísla. """ return a + b def test_secti_kladna_cisla(): assert secti(2, 3) == 5 def test_secti_zaporna_cisla(): assert secti(-2, -3) == -5 def test_secti_nula(): assert secti(2, 0) == 2 ```
    V tomto kódu:
    • Definujeme funkci `secti` pro sčítání dvou čísel.
    • Definujeme testovací funkce s předponou `test_`.
    • Používáme `assert` pro ověření, zda je výsledek sčítání správný.
    Spuštění testů s PyTestem je jednoduché. Stačí spustit příkaz `pytest` v terminálu ve stejném adresáři, kde se nachází testovací soubor. Výsledky testu se zobrazí v terminálu.
  • Uživatel by se mohl zeptat, zda je potřeba instalovat PyTest. Ano, PyTest je nutné instalovat. To lze provést pomocí příkazu `pip install pytest` v terminálu.
  • Instalace PyTestu je jednoduchá. Stačí spustit příkaz `pip install pytest` v terminálu.

    Testování třídy

    Třídy jsou základním stavebním blokem objektově orientovaného programování v Pythonu. Testování tříd je nezbytné pro zajištění správné funkčnosti metod, atributů a vzájemné spolupráce mezi nimi.

    Příklad s unittest

    Následující příklad ukazuje, jak testovat třídu s využitím modulu unittest.
    ```python import unittest class Kalkulator: def __init__(self): self.vysledek = 0 def secti(self, a, b): self.vysledek = a + b return self.vysledek def odecti(self, a, b): self.vysledek = a - b return self.vysledek class TestKalkulator(unittest.TestCase): def setUp(self): self.kalkulator = Kalkulator() def test_secti(self): self.assertEqual(self.kalkulator.secti(2, 3), 5) def test_odecti(self): self.assertEqual(self.kalkulator.odecti(5, 2), 3) def test_vysledek(self): self.kalkulator.secti(2, 3) self.assertEqual(self.kalkulator.vysledek, 5) ```
    V tomto příkladu definujeme třídu Kalkulator, která má metody secti a odecti a atribut vysledek.
    Pro testování třídy Kalkulator vytvoříme třídu TestKalkulator, která dědí z unittest.TestCase. Tato třída obsahuje testovací metody (test_secti, test_odecti, test_vysledek), které ověřují správné chování metod a atributů třídy Kalkulator.
    Metoda setUp se spustí před každým testem a inicializuje objekt Kalkulator.
    V testech používáme metody assertEqual, assertNotEqual, assertTrue, assertFalse a další, abychom ověřili očekávané výsledky.
  • Uživatel by se mohl zeptat, jak testovat metody, které vrací objekt.
  • Uživatel by se mohl zeptat, jak testovat metody s bočními efekty (např. metody, které zapisují do souboru).
  • Příklad s PyTest

    PyTest nabízí elegantnější a intuitivnější syntaxi pro testování. Připravili jsme pro vás příklad, jak testovat třídu s PyTestem.
    ```python from calculator import Kalkulator def test_secti(self): kalkulator = Kalkulator() assert kalkulator.secti(2, 3) == 5 def test_odecti(self): kalkulator = Kalkulator() assert kalkulator.odecti(5, 2) == 3 def test_vysledek(self): kalkulator = Kalkulator() kalkulator.secti(2, 3) assert kalkulator.vysledek == 5 ```
    V PyTestu si s definicí testovací funkce nemusíme lámat hlavu s děděním od unittest.TestCase. Funkce s názvem začínající na test_ se automaticky rozpozná jako testovací funkce a spustí se v PyTestu.
    Pomocí asercí (assert) ověřujeme očekávané výsledky. Pokud aserce selže, test selže a PyTest zobrazí chybovou zprávu.
  • Uživatel by se mohl zeptat, jak pracovat s parametrickými testy, které testují funkci s různými vstupními daty.
  • Uživatel by se mohl zeptat, jak spravovat závislosti v testech, které vyžadují externí zdroje dat.
  • Testování interakce mezi třídami

    Nyní se podíváme na to, jak testovat interakce mezi různými třídami v Pythonu. To je důležité, protože v reálných aplikacích se třídy často vzájemně ovlivňují a je nutné zajistit, aby jejich interakce fungovala správně.
    Ukážeme si, jak napsat testy pro interakce mezi třídami pomocí obou testovacích nástrojů -
    unittest
    a
    PyTest
    .

    Příklad s unittest

    Představte si, že máte třídu
    Order
    reprezentující objednávku a třídu
    Customer
    reprezentující zákazníka. Chceme otestovat interakce mezi těmito třídami, například to, že objednávka je správně přiřazena zákazníkovi.
    Zde je příklad kódu s testem pro tuto situaci:
     class Customer:
         def __init__(self, name, email):
             self.name = name
             self.email = email
    
     class Order:
         def __init__(self, customer, product, quantity):
             self.customer = customer
             self.product = product
             self.quantity = quantity
    
         def get_total_price(self):
             # Vrátí cenu objednávky
             # ...
    
     class TestOrder(unittest.TestCase):
         def test_order_creation(self):
             customer = Customer("Jan Novák", "jan.novak@email.cz")
             order = Order(customer, "Mobilní telefon", 1)
             self.assertEqual(order.customer, customer) # Ověřuje, že objednávka je správně přiřazena zákazníkovi
             self.assertEqual(order.product, "Mobilní telefon")
             self.assertEqual(order.quantity, 1)
    
         def test_get_total_price(self):
             # Vytvoření zákazníka a objednávky
             # ...
             order = Order(customer, "Notebook", 1)
             self.assertEqual(order.get_total_price(), expected_price) # Ověřuje, že cena objednávky je správná
     
    Tento test ověřuje, zda je objednávka správně přiřazena zákazníkovi a zda je cena objednávky správná. V testovacím kódu se vytváří instance třídy
    Customer
    a
    Order
    . Dále se pomocí
    assertEqual
    ověřují očekávané vlastnosti objektu
    Order
    - přiřazení zákazníka a správné nastavení produktu a množství.
  • Uživatel by se mohl zamyslet nad tím, jak testovat více komplexní interakce mezi třídami, například interakce s externími moduly nebo databázemi. V takových případech je vhodné využít techniky
    mockování
    a
    patchování
    , které popíšeme v pozdějších kapitolách.
  • Příklad s PyTest

    Stejný test z předchozího příkladu lze napsat s PyTest:
     def test_order_creation(customer, product, quantity):
         customer = Customer("Jan Novák", "jan.novak@email.cz")
         order = Order(customer, product, quantity)
         assert order.customer == customer
         assert order.product == product
         assert order.quantity == quantity
    
     def test_get_total_price(customer, product, quantity, expected_price):
         # Vytvoření zákazníka a objednávky
         # ...
         order = Order(customer, product, quantity)
         assert order.get_total_price() == expected_price
     
    V PyTest se testy definují s klíčovým slovem
    def
    , a jejich názvy začínají
    test_
    . Pro ověření se používá
    assert
    statement.
    Tento příklad ukazuje, jak testovat interakce mezi třídami v Pythonu. Základní principy testování interakce mezi třídami jsou stejné pro
    unittest
    a
    PyTest
    . Volba nástroje závisí na vašich preferencích a na potřebách projektu.

    Testování API

    Testování API je klíčové pro zajištění správné funkčnosti a stability vaší aplikace, když komunikuje s externími službami. Python nabízí několik nástrojů pro testování API, včetně modulů `requests` a `unittest` nebo frameworku `PyTest`. V této sekci si ukážeme základní příklady testování API s pomocí obou přístupů.

    Příklad s requests a unittest

    V tomto příkladu si ukážeme, jak otestovat API s použitím knihovny `requests` pro komunikaci s API a modulu `unittest` pro definování a spuštění testů. Předpokládáme, že máme k dispozici API, které vrací JSON s informací o počasí, a chceme otestovat, zda API vrací správné údaje.
    ```python import unittest import requests class WeatherAPI_test(unittest.TestCase): def test_api_response(self): # Vytvoříme požadavek na API response = requests.get("https://api.openweathermap.org/data/2.5/weather?q=London&appid=YOUR_API_KEY") # Ověříme, zda byl požadavek úspěšný self.assertEqual(response.status_code, 200) # Ověříme, zda API vrací JSON self.assertEqual(response.headers['Content-Type'], 'application/json') # Získáme data z JSON odpovědi data = response.json() # Ověříme, zda API vrací správné město self.assertEqual(data['name'], 'London') # Ověříme, zda API vrací správné informace o teplotě self.assertTrue(data['main']['temp'] > 0) # Předpokládáme, že teplota bude kladná if __name__ == '__main__': unittest.main() ```
    V tomto kódu definujeme testovací třídu `WeatherAPI_test` s metodou `test_api_response()`. Tato metoda ověřuje:
    • Zda byl požadavek na API úspěšný (status code 200).
    • Zda API vrací JSON.
    • Zda API vrací správné město.
    • Zda API vrací kladnou teplotu.
  • Může být nutné v tomto kódu nahradit placeholdery "YOUR_API_KEY" a "London" dle vašich potřeb. Dále je důležité si uvědomit, že tento kód je pouze základní příklad, který demonstruje princip testování API. V reálných projektech by testy měly být komplexnější a pokrývat více scénářů.
  • Příklad s PyTest

    PyTest nabízí intuitivní syntax pro testování. Níže si ukážeme testovací kód pro API s použitím PyTest.
    ```python import pytest import requests def test_api_response(): response = requests.get("https://api.openweathermap.org/data/2.5/weather?q=London&appid=YOUR_API_KEY") assert response.status_code == 200 assert response.headers['Content-Type'] == 'application/json' data = response.json() assert data['name'] == 'London' assert data['main']['temp'] > 0 ```
    Tento kód je jednodušší a lépe čitelný. PyTest používá `assert` k ověřování podmínek. Kód testuje stejné aspekty jako předchozí příklad.
  • Podobně jako v předchozím příkladu je potřeba nahradit "YOUR_API_KEY" a "London" dle vašich potřeb.
  • Mockování a patchování

    Mockování a patchování jsou pokročilé techniky testování, které se používají k nahrazení částí kódu simulací (tzv. "mocks") a tím umožňují izolovat část kódu, kterou chceme testovat. To je užitečné v situacích, kdy testovaný kód:
    • závisí na externích faktorech, jako jsou sítě, databáze, soubory, jiný software, atd.,
    • vyžaduje časově náročné operace (např. webové požadavky, složité výpočty),
    • může způsobit nežádoucí vedlejší efekty (např. změny v databázi),
    • je obtížné testovat v izolovaném prostředí.
    Mockování a patchování nám umožňují nahradit tyto závislosti jednoduššími simulací, které se snaží co nejvíce napodobit chování skutečného kódu. Tím se snižuje složitost testů, zrychluje jejich provedení a umožňuje nám lépe izolovat a testovat konkrétní části kódu.

    Základní principy

    Mockování a patchování se v Pythonu provádí pomocí modulů
    unittest.mock
    a
    patch
    . Modul
    unittest.mock
    poskytuje nástroje pro vytváření simulací, zatímco
    patch
    slouží k dočasné náhradě funkcí nebo metod během testu.
    Mock je objekt, který reprezentuje simulaci skutečného objektu. Mock může mít definovanou metodu `side_effect`, která vrací specifické výsledky při volání. Můžeme také definovat, kolikrát se mock má volat, nebo zda se má volat vůbec.
    Patch je nástroj pro dočasnou náhradu funkcí nebo metod během testování. Pomocí dekorátoru `@patch` můžeme "zapačovat" danou funkci nebo metodu simulací. Patch umožňuje nám otestovat, jak testovaný kód interaguje s touto nahrazenou částí kódu.
  • Uživatel by mohl mít problémy s pochopením rozdílu mezi mockováním a patchováním.
  • Uživatel by mohl mít problémy s pochopením, jak se používá dekorátor
    @patch
    a jak funguje v kontextu testů.
  • Použití mockování v testování

    Následující příklad ukazuje, jak mockovat funkci `get_data` a simulovat její chování v testu. Funkce `get_data` v tomto příkladu reprezentuje funkci, která získává data z externího zdroje, například z databáze, webového API nebo souboru.
    import unittest
    from unittest.mock import patch, MagicMock
    
    def zpracuj_data(data):
        return data.upper()
    
    class TestZpracujData(unittest.TestCase):
        @patch('modul.get_data')
        def test_zpracuj_data(self, mock_get_data):
            mock_get_data.return_value = 'ahoj svět!'
            vysledek = zpracuj_data(mock_get_data())
            self.assertEqual(vysledek, 'AHOJ SVĚT!')
    
    V tomto testu nahradíme funkci `get_data` simulací `mock_get_data`. Nastavíme výsledek volání simulace na 'ahoj svět!' a ověříme, zda funkce `zpracuj_data` vrací správný výsledek (v tomto případě 'AHOJ SVĚT!').
  • Uživatel by mohl mít problémy s pochopením, proč je nutné mockovat funkci `get_data` a jak se simuluje její chování v testu.
  • Uživatel by mohl mít problémy s pochopením, jak funguje mockování v kontextu funkce `zpracuj_data` a jak se používá v testu.
  • V tomto příkladu jsme použili funkci `MagicMock`, která nám dává větší kontrolu nad simulací. Funkce `return_value` nastaví výsledek volání simulace a můžeme také definovat chování simulace pro různé argumenty.
    Mockování a patchování jsou důležitými nástroji pro vytváření komplexních a robustních testů. Umožňují nám izolovat testovanou část kódu a ověřit její chování bez závislosti na externích faktorech. To nám umožňuje testovat kód efektivně a bez rizika nežádoucích vedlejších efektů.

    Testování s datovými soubory

    Testování s datovými soubory je užitečné, když potřebujete otestovat funkci, která zpracovává data z externího zdroje, jako je soubor, databáze nebo API. Místo přímého přístupu k tomuto externímu zdroji v testech si vytvoříte testovací data v souboru, který pak použijete pro testování.

    Příprava testovacích dat

    Testovací data by měla zahrnovat různé scénáře, které vaše funkce zpracovává. Měli byste mít data, která představují:
    • Správné vstupy, které vaše funkce správně zpracuje.
    • Neplatné vstupy, které by měly vyvolat chybu nebo ošetření chyby.
    • Hranicové případy, které testují, jak vaše funkce reaguje na mezní hodnoty.
    Data si můžete připravit v jakémkoli vhodném formátu, jako je CSV, JSON, XML nebo YAML. Doporučuje se data uložit do samostatného souboru, aby se testy daly snadno upravovat a udržovat.
  • Uživatel by se mohl potýkat s volbou vhodného formátu testovacích dat a s přípravou dat pro různé scénáře.
  • Použití testovacích dat v testech

    V testech pak načítáte data z testovacího souboru a předáte je testované funkci. Můžete ověřovat, zda funkce vrací očekávaný výstup, nebo zda vyvolá očekávanou chybu.
    Ukázka testu s použitím datového souboru (v tomto případě JSON):
    import unittest
    import json
    
    def zpracuj_data(data):
        # Zpracování dat...
    
    class TestZpracujData(unittest.TestCase):
    
        def test_zpracuj_data_spravne(self):
            with open('test_data.json', 'r') as f:
                data = json.load(f)
            vysledek = zpracuj_data(data)
            # Ověření očekávaného výsledku...
    
        def test_zpracuj_data_neplatne(self):
            with open('test_data_neplatna.json', 'r') as f:
                data = json.load(f)
            with self.assertRaises(ValueError):
                zpracuj_data(data)
    
    if __name__ == '__main__':
        unittest.main()
    
  • Uživatel by mohl mít problémy s načtením dat z testovacího souboru a s jejich zpracováním v testu. Je důležité si vybrat správný formát souboru a použít příslušnou knihovnu pro jeho načtení (např.
    json
    pro JSON,
    csv
    pro CSV).
  • TDD (Test-Driven Development)

    TDD (Test-Driven Development) je softwarový vývojový proces, který klade důraz na psaní testů dříve, než je napsán samotný kód. Princip TDD spočívá v opakování tří kroků:
    • Napsat test: Nejdříve se napíše test, který definuje požadované chování funkce (nebo komponenty). Test v této fázi obvykle selže, protože se testy spouští předtím, než je funkce implementována.
    • Implementovat kód: Následně se naprogramuje funkce tak, aby prošla testem. V této fázi se snažíme psát nejjednodušší kód, který splní daný test.
    • Refaktorovat kód: Po provedení testu se můžeme zaměřit na optimalizaci a zjednodušení kódu, aniž bychom se obávali, že změníme chování programu. Testovací soubor nám dává jistotu, že naše optimalizace nesníží funkčnost.

    Postup TDD

    TDD se obvykle realizuje pomocí cyklů, kde se opakují výše uvedené kroky pro každou novou funkcionalitu, která se má přidat do programu. Během vývoje by se mělo dodržovat několik zásad:
    • Napsat jen jeden test: Testy by se měly psát po jednom, aby se otestovala pouze jedna specifická funkcionalita.
    • Udržovat testy co nejjednodušší: Testy by měly být co nejmenší a nejjasnější.
    • Spouštět testy po každé implementaci: Je důležité pravidelně spouštět testy, aby se ověřilo, že kód funguje správně.
  • Uživatel by mohl mít problémy s pochopením, jak se testy píší a spouštějí před implementací kódu.
  • Uživatel by mohl mít problémy s pochopením, jak se testy používají pro refaktoring kódu.
  • Shrnutí klíčových bodů

    V tomto tutoriálu jsme probrali základy testování softwaru v Pythonu a seznámili se s důležitými koncepty a nástroji. Zjistili jsme, že testování je klíčovým aspektem kvalitního vývoje softwaru, který nám umožňuje:
    • Zjistit a opravit chyby v kódu dříve, než se dostanou do produkčního prostředí.
    • Zlepšit kvalitu kódu a zaručit jeho stabilitu.
    • Urychlit vývoj a zjednodušit údržbu softwaru.
    Naučili jsme se základní principy a struktury testů v modulu
    unittest
    a seznámili jsme se s populárním frameworkem
    PyTest
    .
    Získali jsme znalosti o různých typech testů, včetně:
    • Unit testy pro testování jednotlivých funkcí.
    • Integrační testy pro testování interakcí mezi komponentami.
    • Funkční testy pro testování celého systému.
    • Regresní testy pro kontrolu zachování funkčnosti po změnách.
    Pochopením těchto konceptů máte solidní základ pro psaní efektivních a komplexních testů pro vaše Python aplikace.
  • Uživatel by si mohl myslet, že testování je příliš složité a časově náročné, ale je důležité si uvědomit, že testování v konečném důsledku šetří čas a peníze.
  • Další zdroje a tipy

    • Oficiální dokumentace unittest: https://docs.python.org/3/library/unittest.html - Zde naleznete podrobnější informace o modulu unittest, včetně popisu všech dostupných metod a funkcí.
    • Oficiální dokumentace PyTest: https://docs.pytest.org/en/latest/ - Tato dokumentace nabízí podrobný návod k použití PyTest, včetně pokročilých funkcí, pluginů a příkladů.
    • Kniha "Testing in Python" od Brian Okken: Tato online kniha poskytuje komplexní přehled testovacích metod v Pythonu a zahrnuje mnoho praktických příkladů.
    • Kurz "Python Testing Fundamentals" na Coursera: Tento bezplatný kurz vám pomůže osvojit si základy testování v Pythonu a naučí vás používat moduly unittest a PyTest.
    • Online články a tutoriály: V internetovém prostředí existuje mnoho článků a tutoriálů o testování v Pythonu. Hledejte tipy a rady pro různé typy testů a specifické situace.
    • Komunita Pythonu: Zapojte se do komunity Pythonu na fórech, serverech Discordu a dalších platformách. Ptejte se zkušenějších vývojářů na rady a sdílejte své zkušenosti s testováním.
  • Uživatel by mohl mít problémy s nalezením relevantních online zdrojů a tutoriálů. Doporučuji mu použít klíčová slova jako "python testing", "unittest", "pytest" a "test-driven development".