Uživatelské nástroje

Nástroje pro tento web


testovaci_pyramidy

Testovací pyramida

Testovací pyramida je koncept v softwarovém inženýrství, který vizualizuje doporučené poměry a hierarchii různých typů testů v softwarovém projektu. Tento model poprvé formuloval Mike Cohn ve své knize *Succeeding with Agile* (2009) a od té doby se stal základním principem pro budování udržitelné a efektivní testovací strategie.

Cílem testovací pyramidy je:

  • minimalizovat náklady na testování,
  • maximalizovat rychlost zpětné vazby,
  • zvýšit spolehlivost testovací sady,
  • a podpořit rychlý vývoj s vysokou kvalitou.

Struktura testovací pyramidy

Pyramida se skládá ze tří hlavních vrstev, uspořádaných od nejrychlejších a nejlevnějších testů (spodek) po nejpomalejší a nejnákladnější (vrchol):

1. Jednotkové testy (Unit Tests) – základna pyramidy

  • Co testují: Izolované jednotky kódu (např. funkce, metody, třídy).
  • Rychlost: Milisekundy – spouští se běžně stovky až tisíce za sekundu.
  • Náklady na údržbu: Nízké.
  • Stabilita: Vysoká – selhávají jen při změně logiky.
  • Doporučený podíl: 70 % a více všech automatizovaných testů.
💡 Dobrý jednotkový test je rychlý, izolovaný, deterministický a snadno čitelný.

2. Integrační testy (Integration Tests) – střední vrstva

  • Co testují: Interakce mezi více komponentami nebo systémy (např. volání databáze, API, služby třetích stran).
  • Rychlost: Desítky milisekund až sekundy.
  • Náklady na údržbu: Střední – závisí na složitosti integrací.
  • Stabilita: Střední – mohou selhat kvůli externím závislostem.
  • Doporučený podíl: 20–25 % testů.
💡 Integrační testy ověřují, že části systému „spolu hrají“ správně.

3. End-to-end (E2E) testy – vrchol pyramidy

  • Co testují: Kompletní uživatelské scénáře napříč celou aplikací (např. „uživatel se přihlásí, přidá zboží do košíku a zaplatí“).
  • Rychlost: Sekundy až minuty.
  • Náklady na údržbu: Vysoké – citlivé na změny UI.
  • Stabilita: Nízká – často selhávají kvůli dočasným problémům (časování, síť).
  • Doporučený podíl: 5–10 % testů.
💡 E2E testy simulují skutečného uživatele, ale nejsou náhradou za jednotkové testy!

Vizuální znázornění pyramidy

          ┌───────────────────┐
          │  End-to-End testy │ ← málo, pomalé, drahé
          └───────────────────┘
        ┌───────────────────────┐
        │   Integrační testy    │ ← střední množství
        └───────────────────────┘
┌───────────────────────────────────┐
│        Jednotkové testy           │ ← hodně, rychlé, levné
└───────────────────────────────────┘

Konkrétní příklady testů

Jednotkový test v Pythonu (s pytest)

Soubor: `calculator.py`

def divide(a, b):
    if b == 0:
        raise ValueError("Dělení nulou není povoleno")
    return a / b

Soubor: `test_calculator.py`

import pytest
from calculator import divide
 
def test_divide_positive_numbers():
    assert divide(10, 2) == 5.0
 
def test_divide_by_zero_raises_error():
    with pytest.raises(ValueError, match="Dělení nulou není povoleno"):
        divide(5, 0)
✅ Rychlé, izolované, bez závislostí – ideální jednotkový test.

Jednotkový test v Javě (s JUnit 5)

Soubor: `BankAccount.java`

public class BankAccount {
    private double balance;
 
    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }
 
    public void withdraw(double amount) {
        if (amount > balance) {
            throw new IllegalArgumentException("Nedostatek prostředků");
        }
        balance -= amount;
    }
 
    public double getBalance() {
        return balance;
    }
}

Soubor: `BankAccountTest.java`

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
 
class BankAccountTest {
 
    @Test
    void withdraw_ValidAmount_ReducesBalance() {
        BankAccount account = new BankAccount(100.0);
        account.withdraw(30.0);
        assertEquals(70.0, account.getBalance());
    }
 
    @Test
    void withdraw_InsufficientFunds_ThrowsException() {
        BankAccount account = new BankAccount(50.0);
        assertThrows(IllegalArgumentException.class, () -> account.withdraw(60.0));
    }
}

Integrační test v Pythonu (s databází pomocí Testcontainers)

import pytest
from sqlalchemy import create_engine, text
from myapp.models import User
 
@pytest.fixture(scope="module")
def db_engine():
    # Spustí Docker kontejner s PostgreSQL (přes testcontainers)
    with PostgresContainer("postgres:15") as postgres:
        engine = create_engine(postgres.get_connection_url())
        yield engine
 
def test_user_persistence(db_engine):
    # Vložíme uživatele do DB
    with db_engine.connect() as conn:
        conn.execute(text("INSERT INTO users (name) VALUES ('Alice')"))
        result = conn.execute(text("SELECT name FROM users WHERE name = 'Alice'"))
        assert result.fetchone()[0] == "Alice"

E2E test v Javě (s Playwright)

import com.microsoft.playwright.*;
import org.junit.jupiter.api.*;
 
public class LoginE2ETest {
    static Playwright playwright;
    static Browser browser;
 
    @BeforeAll
    static void launchBrowser() {
        playwright = Playwright.create();
        browser = playwright.chromium().launch();
    }
 
    @Test
    void successfulLogin() {
        Page page = browser.newPage();
        page.navigate("https://mojeaplikace.cz/login");
        page.fill("#username", "admin");
        page.fill("#password", "heslo123");
        page.click("button[type='submit']");
        assertTrue(page.url().contains("/dashboard"));
        assertTrue(page.textContent("h1").contains("Vítejte"));
    }
 
    @AfterAll
    static void closeBrowser() {
        playwright.close();
    }
}

Testovací matice pro mikroslužby

V architektuře mikroslužeb se klasická pyramida rozšiřuje o testovací matici, která zohledňuje:

  • Vertikální vrstvy (jednotkové → integrační → E2E),
  • Horizontální dimenzi (testování uvnitř služby vs. mezi službami).
Úroveň testování Uvnitř služby Mezi službami (síť)
Jednotkové testy Test logiky bez závislostí
Integrační testy Test s databází, cache, externí API Kontraktové testy (Pact), Consumer-Driven Contracts
E2E / Špičkové testy Kompletní workflow přes více služeb (např. objednávka → platba → doručení)
🔑 Klíčový princip: Nejdříve otestujte logiku uvnitř služby, pak ověřte smlouvy mezi službami, a až nakonec spusťte nákladné E2E testy.

Tento přístup minimalizuje závislost na „živém“ prostředí a zvyšuje izolaci testů.

Proč dodržovat testovací pyramidu?

  • Rychlá zpětná vazba: Jednotkové testy selžou během sekund, nikoli minut.
  • Nižší náklady: Údržba 1000 jednotkových testů je levnější než 10 E2E testů.
  • Lepší laditelnost: Když selže jednotkový test, víte přesně, kde je chyba.
  • Vyšší pokrytí: Lze snadno pokrýt okrajové případy (edge cases).
  • Bezpečný refaktoring: Spolehlivá síť jednotkových testů umožňuje bez obav upravovat kód.

Běžné antipatterny

Testovací kužel (Ice-Cream Cone)

  • Příliš mnoho manuálních nebo E2E testů,
  • Nedostatek jednotkových testů,
  • Důsledek: Pomalé buildy, nestabilní testy, nízká důvěra v automatizaci.

Testovací kobliha (Testing Cupcake)

  • Tým má jen E2E testy a žádné jednotkové/integrační,
  • Vývoj je pomalý, chyby se hledají hodiny.

Přehnaná automatizace UI

  • Každý požadavek se testuje E2E testem,
  • Vede k „testovací dlužné pasti“ – testy jsou dražší než kód samotný.

Nástroje podle vrstvy

Vrstva Příklady nástrojů
——–——————-
Jednotkové testy JUnit, pytest, NUnit, Jest, Mocha
Integrační testy Testcontainers, Pact, Postman, REST Assured
E2E testy Cypress, Playwright, Selenium, WebdriverIO
BDD testy Cucumber, SpecFlow, Behave (často nad E2E nebo integrační vrstvou)

Související pojmy

Externí odkazy

Viz také

testovaci_pyramidy.txt · Poslední úprava: autor: admin