Test-Driven Development (TDD) — je metodologie vývoje, při které se testy píší před implementací kódu. Vývojář nejprve formuluje očekávané chování v podobě padajícího testu, poté napíše minimální kód pro jeho průchod a po tomto výsledek refaktoruje. Podle Martin Fowler (2023) TDD není technikou testování — je to technika návrhu, která ukázňuje architekturu a snižuje počet defektů ve fázi psaní kódu.
Hlavní body
Test-Driven Development — je praktika vývoje softwaru, při které automatizované testy určují psaní produkčního kódu. Na rozdíl od tradičního přístupu, kde se kód nejprve napíše a poté testuje, TDD obrací pořadí: nejprve se napíše test, poté kód, který tento test projde.
Za zakladatele TDD je považován Kent Beck, který tuto praktiku formuloval na konci 90. let 20. století v rámci metodologie Extreme Programming (XP). V knize „Test-Driven Development: By Example" (2002) Beck popsal pět pravidel TDD, která se stala kanonickými: napiš test před produkčním kódem, napiš přesně tolik kódu, kolik je potřeba k průchodu testu, a refaktoruj po každém cyklu.
První princip — test definuje rozhraní. Vývojář je nucen přemýšlet o tom, jak bude komponenta používána, dříve než přemýšlí o tom, jak je implementována. To formuje čisté API od samého začátku.
Druhý princip — minimální implementace. Když je test napsán, vývojář napíše přesně tolik produkčního kódu, kolik je potřeba k jeho průchodu — ani řádek navíc. To zabraňuje předčasné abstrakci a nadměrné komplexitě, kterou Martin Fowler nazývá Speculative Generality.
Klíčový rozdíl mezi TDD a testováním „dodatečně" — disciplína pořadí. V TDD test nejen kontroluje kód — ale řídí jeho strukturu. Podle výzkumu Microsoft Research (Nagappan et al., 2008) vykazují týmy aplikující TDD snížení hustoty defektů o 40–90 % ve srovnání s týmy používajícími tradiční přístup.
Cyklus Red-Green-Refactor — je tříkroková sekvence opakovaná pro každý nový test. Red: napiš test, který neprojde. Green: napiš minimální kód, aby test prošel. Refactor: vylepši kód bez změny jeho chování.
Vývojář napíše test, který kontroluje dosud neimplementovanou funkcionalitu. V této fázi by měl test padnout — to potvrzuje, že test skutečně něco kontroluje. Ve vývojovém prostředí Android framework JUnit 5 zobrazuje červenou indikaci pro padlé testy, což dalo fázi jméno.
class CalculatorTest {
fun testAddition() {
val result = Calculator().add(2, 3)
Assertions.assertEquals(5, result)
}
}
V této fázi se píše minimální produkční kód dostatečný pro průchod testu. Žádná redundance — pouze to, co je potřeba pro zelenou indikaci. Pokud implementace může být konstanta — ať je konstanta. Refaktorování proběhne v dalším kroku, když se objeví nové testy.
class Calculator {
fun add(a: Int, b: Int): Int {
return a + b
}
}
Zelený test je pojištění pro refaktorování. Vývojář může přepsat implementaci, optimalizovat výkon nebo zlepšit čitelnost, s jistotou, že test okamžitě odhalí jakoukoli odchylku od očekávaného chování. V mobilním vývoji na Androidu je tato fáze obzvláště důležitá pro vyčlenění společných rozhraní a snížení duplicity kódu.
Aplikace TDD v mobilních projektech přináší měřitelné výhody, potvrzené jak akademickým výzkumem, tak praxí předních vývojářských studií.
Výzkum IBM (Bhat & Nagappan, 2006) na čtyřech průmyslových projektech ukázal, že týmy používající TDD dělají o 40 % méně defektů ve srovnání s podobnými týmy pracujícími tradičně. Pro mobilní vývoj, kde jsou náklady na opravu chyby po vydání v Google Play výrazně vyšší než ve fázi psaní kódu, je tato metrika kritická.
Testy napsané podle TDD slouží jako živá dokumentace API. Vývojář přicházející do projektu může číst testy a pochopit, jak má být každá komponenta používána. To je obzvláště cenné v podmínkách vysoké fluktuace týmu — typického problému mobilních studií.
Pokrytí kódu testy přesahující 90 % umožňuje vývojářům provádět refaktorování bez strachu, že něco rozbijí. Google ve své knize „Software Engineering at Google" (2020) nazývá pokrytí testy klíčovým faktorem, který umožňuje udržovat kódovou základnu čistou v projektech s miliony řádků kódu.
Ekosystém TDD v mobilním vývoji zahrnuje nástroje pro unit testy, mocking a kontrolu UI komponent — jak pro Android, tak pro iOS.
| Nástroj | Platforma | Účel |
|---|---|---|
| JUnit 5 | Android (Kotlin/Java) | Základní framework pro unit testy |
| Mockito | Android | Vytváření mock objektů a ověřování volání |
| MockK | Android (Kotlin) | Mocking se syntaxí Kotlin-first a podporou korutin |
| Turbine | Android | Testování Kotlin Flow a reaktivních toků |
| XCTest | iOS (Swift) | Standardní testovací framework |
Pro Android projekty v Kotlinu standardní stack zahrnuje JUnit 5 + MockK. MockK je preferován před Mockito, protože podporuje funkce Kotlin první třídy — sealed class, korutiny a suspend-funkce bez dodatečné konfigurace.
Ve vývoji pro iOS je TDD implementován prostřednictvím XCTest — vestavěného frameworku Apple, který poskytuje aserce, testovací třídy a integraci s CI/CD přes Xcode Server nebo GitHub Actions. Pro mocking na iOS se používají knihovny Cuckoo a OHHTTPStubs.
Podívejme se na reálný scénář TDD v Kotlinu pro Android — testování uživatelského repozitáře. Nejprve napíšeme test, poté — implementaci, která tímto testem projde.
class UserRepositoryTest {
private val api = mockk<UserApi>()
private val dao = mockk<UserDao>()
private val repo = UserRepository(api, dao)
fun `when api returns user then cache and emit`() = runTest {
val user = User(1, "Alice")
coEvery { api.getUser(1) } returns user
every { dao.insert(user) } returns Unit
val result = repo.getUser(1)
assertEquals(user, result)
verify { dao.insert(user) }
}
}
class UserRepository(
private val api: UserApi,
private val dao: UserDao
) {
suspend fun getUser(id: Int): User {
val user = api.getUser(id)
dao.insert(user)
return user
}
}
Po průchodu prvního testu přidáme druhý — kontrolujeme chování při chybě sítě. Nyní test určuje, že při pádu API by měl repozitář vrátit data z mezipaměti.
fun `when api fails then return cached user`() = runTest {
val cached = User(1, "Cached Alice")
coEvery { api.getUser(1) } throws IOException()
every { dao.getById(1) } returns cached
val result = repo.getUser(1)
assertEquals(cached, result)
}
Přechod na TDD je doprovázen typickými chybami, které mohou anulovat všechny výhody metodologie. Pochopení těchto nástrah pomáhá týmům zavádět praktiku efektivněji.
První a nejrozšířenější anti-vzor — testování příliš velkého rozsahu funkcionality v jednom testu. Test by měl kontrolovat přesně jedno tvrzení (jednu aserci). Pokud test spadne, vývojář by měl vědět, co přesně se rozbilo, bez dodatečného ladění.
Druhá chyba — napsání testu, který od začátku prochází. Pokud test nebyl alespoň jednou červený, není jistota, že vůbec něco kontroluje. Pravidlo: nikdy nevěř testu, který jsi neviděl padat.
Třetí typická chyba — zastavení v zelené fázi. Refaktorování není volitelná, ale povinná fáze cyklu. Bez něj kódová základna degraduje, testy se stávají křehkými a výhody TDD se ztrácejí.
Často kladené otázky
TDD je především technika návrhu, nikoli testování. Testy v TDD hrají roli specifikace: definují API komponenty před její implementací. Sám Kent Beck nazývá TDD „disciplínou návrhu, nikoli testování".
Podle výzkumů Microsoft Research týmy potřebují 3 až 6 měsíců nepřetržité praxe, aby se TDD stal zvykem. První 2–3 týdny produktivita klesá o 15–30 %, ale po adaptaci se vrací na původní úroveň nebo ji překonává díky zkrácení doby ladění.
Ano, ale s omezeními. Pro UI logiku (ViewModel, State) je TDD použitelné přímo. Pro vizuální komponenty (Compose UI, SwiftUI Views) testování snímky obrazovky (snapshot testing) TDD doplňuje, ale nenahrazuje. Doporučuje se oddělovat obchodní logiku od zobrazení.
Pro legacy kód se doporučuje strategie „charakterizačních testů" (characterization tests) — kdy se testy píší na stávající chování a poté se kód refaktoruje. Tento přístup popsaný v knize Michaela Featherse „Working Effectively with Legacy Code" (2004) umožňuje postupné zavádění TDD.
TDD a Clean Architecture se vzájemně posilují. Čistá architektura vyžaduje jasné hranice mezi vrstvami a TDD nutí vývojáře tyto hranice navrhovat prostřednictvím testů. Doménová vrstva se testuje izolovaně s mock závislostmi, datová vrstva — prostřednictvím integračních testů.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také