Upozornění pro čtenáře a uživatele této knihy
Všechna práva vyhrazena. Žádná část této tištěné či elektronické knihy nesmí být reprodukována ani šířena v papírové, elektronické či jiné podobě bez předchozího písemného souhlasu nakladatele. Neoprávněné užití této knihy bude trestně stíháno.

Arnošt Havelka a Rudolf Pecinovský

JUnit 5
Jednotkové testování na platformě Java

Vydala Grada Publishing, a.s.
U Průhonu 22, Praha 7
obchod@grada.cz, www.grada.cz
tel.: +420 234 264 401, fax: +420 234 264 400
jako svou 7022. publikaci

Odpovědný redaktor: Petr Somogyi
Návrh vnitřního layoutu: Rudolf Pecinovský
Zlom: Rudolf Pecinovský
Formát ePub: Štěpán Böhm
Počet stran 296
První vydání, Praha 2018
Vytiskly Tiskárny Havlíčkův Brod, a. s.

© Grada Publishing, a.s., 2018
Cover Design © Grada Publishing, a. s., 2018
Cover Photo © Depositphotos

Názvy produktů, firem apod. použité v knize mohou být ochrannými známkami nebo registrovanými ochrannými známkami příslušných vlastníků.

ISBN 978-80-247-1496-7 (ePub)
ISBN 978-80-247-1225-3 (pdf)
ISBN 978-80-271-0733-9 (print)

Ing. Arnošt Havelka je absolventem Fakulty informatiky a statistiky VŠE z roku 2017. Od konce 90. let pracuje (na různých pozicích) v oblasti vývoje softwaru. V současné době pracuje jako nezávislý kontraktor a konzultant pro vývoj IS na platformě Java.

Ing. Rudolf Pecinovský, CSc. je absolventem Fakulty Elektrotechnické ČVUT z roku 1979. Titul CSc. získal v Ústavu teorie informace a automatizace ČSAV v roce 1983. Od počátku 80. let učí a publikuje, přičemž svůj výzkum soustředí především na oblast vstupních kurzů moderního programování pro naprosté začátečníky. V současné době učí na Vysoké škole ekonomické v Praze, na Fakultě jaderné a fyzikálně inženýrské ČVUT a na Vysoké škole podnikání a práva. Doposud mu vyšlo přes 50 knih, které byly přeloženy do pěti jazyků. Většina jeho knih je zaměřena na výuku moderního programování a na umění návrhu objektově orientované architektury.

Seznam programů

Výpis 4.1: Definice třídy Main sloužící ke spouštění testovacích tříd.

Výpis 4.2: Prostoduchá definice testovací třídy TestHelloWorld_v5 a jednotkového testu helloWorld

Výpis 4.3: Výpis zprávy o průběhu testu definovaného ve výpisu 4.2.

Výpis 4.4: Výpis zprávy o výsledku testu definovaného ve výpisu 4.2 v prostředí, které neumí zpracovat nastavení ANSI barev

Výpis 4.5: Třída TestMinMax s ukázkami reálných testovacích metod.

Výpis 4.6: Souhrnná zpráva o průběhu testu definovaného ve výpisu 4.5.

Výpis 4.7: Definice testovací třídy TestHelloWorld_v4.

Výpis 4.8: Definice testovací třídy TestHelloWorld_v3.

Výpis 4.9: Výpis zprávy o průběhu testů při spuštění všech čtyř doposud definovaných testovacích tříd

Výpis 5.1: Definice metody test_assertAll() ve třídě TestAssertAll.

Výpis 5.2: Zestručněná definice funkčního interfejsu ThrowingSupplier<T>.

Výpis 6.1: Definice testovací třídy TestSetUpTearDown.

Výpis 6.2: Výstup testů ve třídě TestSetUpTearDown a úvodní strom ze závěrečného souhrnu

Výpis 6.3: Definice třídy TestAbstractLifeCycle.

Výpis 6.4: Definice třídy TestLifeCycle.

Výpis 6.5: Počátek zprávy o průběhu testů tříd LifeCycleTest a LifeCycle2Test.

Výpis 6.6: Definice testovací třídy TestParamDemo.

Výpis 6.7: Výstup testů TestParamDemo a úvodní strom ze závěrečného souhrnu.

Výpis 6.8: Definice testovací třídy TestTagTags.

Výpis 7.1: Třída TestDisable demonstrující možnosti nepodmíněného zakázání testu.

Výpis 7.2: Třída TestDisableClass demonstrující možnosti nepodmíněného zakázání všech testů dané třídy

Výpis 7.3: Závěrečný souhrn po aktivaci tříd TestDisable a TestDisableClass.

Výpis 7.4: Ukázky použití podmíněného spuštění testu zadáním anotací @DisabledOnJre a @EnabledOnJre

Výpis 7.5: Ukázky použití podmíněného spuštění testu zadáním anotací @DisabledOnOs a @EnabledOnOs

Výpis 7.6: Ukázky použití podmíněného spuštění testu zadáním anotací @DisableIfEnvironmentVariable a @EnableIfEnvironmentVariable.

Výpis 7.7: Ukázky použití podmíněného spuštění testu zadáním anotací @DisabledIfSystemProperty a @EnabledIfSystemProperty.

Výpis 7.8: Ukázky použití podmíněného spuštění testu zadáním anotací @DisabledIf a @EnabledIf

Výpis 7.9: Souhrnná zpráva o průběhu testů ve třídě TestEnableDisable.

Výpis 7.10: Ukázka použití metody assumeTrue.

Výpis 7.11: Ukázka použití metody assumingThat.

Výpis 8.1: Definice třídy TestRepetitions s ukázkami použití opakovaného testu.

Výpis 8.2: Souhrnná zpráva o průběhu testů třídy TestRepetitions.

Výpis 8.3: Definice třídy TestNamedRepetitions s ukázkami vlastního nastavení pro zobrazení názvu instance testu

Výpis 8.4: Souhrnná zpráva o průběhu testů třídy TestNamedRepetitions.

Výpis 8.5: Třída TestSimpleParametrized s definicí jednoduchého parametrického testu.

Výpis 8.6: Strom ze závěrečné zprávy o testech ve třídě TestSimpleParametrized.

Výpis 8.7: Definice třídy TestDefaultTypeConversion.

Výpis 8.8: Úvod zprávy o průběhu testu třídy TestDefaultTypeConversion.

Výpis 8.9: Definice anotace @ValueSource.

Výpis 8.10: Definice třídy TestEnumSource.

Výpis 8.11: Závěrečná zpráva o testech ve třídě TestEnumSource.

Výpis 8.12: Definice třídy TestMethodSource s ukázkami testů s argumenty zadávanými prostřednictvím továrních metod

Výpis 8.13: Strom ze závěrečné zprávy o průběhu testů z třídy TestMethodSource.

Výpis 8.14: Definice třídy TestCsvSource.

Výpis 8.15: Úvod závěrečné zprávy o testu třídy TestCsvSource.

Výpis 8.16: Definice třídy TestCsvFileSource demonstrující možnost zadání argumentů v souborech

Výpis 8.17: Obsah souboru Root.txt

Výpis 8.18: Počátek souhrnné zprávy o průběhu testu třídy TestCsvFileSource.

Výpis 8.19: Definice třídy TestMethodMultiSource demonstrující možnost zadání několika argumentů prostřednictvím metody.

Výpis 8.20: Počátek souhrnné zprávy o průběhu testu třídy TestMethodMultiSource.

Výpis 8.21: Definice třídy TestMultiParam demonstrující možnost použití informačních parametrů

Výpis 8.22: Počátek závěrečné zprávy o testech třídy TestMultiParam.

Výpis 9.1: Definice interfejsu IBeforeAfter definujícího organizační metody a sadu pomocných metod pro zvětšování a zmenšování odsazení.

Výpis 9.2: Definice testovací třídy TestIBeforeAfter.

Výpis 9.3: Úvod závěrečné zprávy o průběhu testů třídy TestIBeforeAfter.

Výpis 9.4: Zdrojový kód třídy TestInner demonstrující využití anotací @Nested a @Tag.

Výpis 9.5: Úvod závěrečné zprávy o průběhu testů třídy TestInner.

Výpis 10.1: Ukázka nastavení stabilní vlastnosti pro anotaci @DisplayName.

Výpis 10.2: Ukázka nastavení experimentální vlastnosti pro anotaci @CsvFileSource.

Výpis 10.3: Ukázka vlastního vyhledání testů (viz [28])

Výpis 10.4: Ukázka vlastního spuštění a vyhodnocení testů (viz [28])

Výpis 10.5: Ukázka izolace testů přes testovací třídu.

Výpis 11.1: Definice rozšíření pro interfejs BeforeEachCallback.

Výpis 11.2: Definice rozšíření pro interfejs AfterEachCallback.

Výpis 11.3: Ukázka testu pro deklarativní registraci rozšíření

Výpis 11.4: Výstup běhu testovací třídy CustomTests.

Výpis 11.5: Definice rozšíření pro správu dočasného adresáře.

Výpis 11.6: Definice rozšíření pro tvorbu dočasných souborů.

Výpis 11.7: Ukázka testu pro programovou registraci rozšíření

Výpis 11.8: Výstup běhu testovací třídy RegisterExtensionTest.

Výpis 11.9: Definice komplexního rozšíření pro zpracování statistik testů.

Výpis 11.10: Definice anotace @Stat.

Výpis 11.11: Ukázka testu využívajícího rozšíření pomocí anotace @Stat.

Výpis 11.12: Výpis z běhu testovací třídy StatTests.

Výpis 12.1: Definice anotace @Hello.

Výpis 12.2: Ukázka implementace třídy ParameterResolver.

Výpis 12.3: Ukázka použití třídy HelloResolver pro vlastní zpracování vstupních parametrů metod

Výpis 12.4: Definice komponenty implementující interfejs TestExecutionExceptionHandler

Výpis 12.5: Ukázka implementace třídy ParameterResolver.

Výpis 12.6: Ukázka testu s parametry pomocí implementace interfejsu ArgumentsProvider.

Výpis 12.7: Ukázka testu s parametry pomocí implementace interfejsu ArgumentsProvider.

Výpis 12.8: Ukázka použití implicitní konverze hodnot pro testy s parametry.

Výpis 12.9: Ukázka definice explicitního konvertoru pomocí interfejsu ArgumentConvertor.

Výpis 12.10: Ukázka použití explicitní konverze pomocí třídy CustomConverter.

Výpis 12.11: Ukázka použití standardního interfejsu ArgumentsAccessor.

Výpis 12.12: Ukázka použití vlastní implementace interfejsu ArgumentsAccessor.

Výpis 12.13: Ukázka vytvoření vlastní anotace @CsvToDrink pro více argumentů.

Výpis 12.14: Ukázka použití vlastní anotace @CsvToDrink pro více argumentů.

Výpis 12.15: Ukázka vyhledání testů pomocí interfejsu Launcher (viz [28], kapitola 7.1)

Výpis 12.16: Ukázka maven konfigurace pluginu maven-surefire-plugin.

Výpis 12.17: Ukázka použití deterministického generátoru testů.

Výpis 12.18: Ukázka použití nedeterministického generování testů.

Výpis 12.19: Definice anotace ParameterizedTest.

Výpis 12.20: Definice třídy ParameterizedTestExtension.

Výpis 13.1: Zapojení frameworku AssertJ do projektu.

Výpis 13.2: Ukázka použití frameworku AssertJ.

Výpis 13.3: Zapojení frameworku Hamcrest do projektu.

Výpis 13.4: Ukázka použití frameworku Hamcrest

Výpis 13.5: Zapojení frameworku Mockito do projektu.

Výpis 13.6: Základní použití frameworku Mockito.

Výpis 13.7: Ukázka použití frameworku Mockito s anotací @Mock.

Výpis 13.8: Ukázka použití frameworku Mockito s anotací @Spy.

Výpis 13.9: Ukázka použití frameworku Mockito s anotací @Captor.

Výpis 13.10: Zapojení frameworku Mockito do projektu.

Výpis 13.11: Základní použití frameworku EasyMock.

Výpis 13.12: Ukázka použití frameworku EasyMock s anotací @Mock.

Výpis 13.13: Ukázka použití testu na privátní konstruktor třídy.

Výpis 13.14: Zapojení frameworku PowerMock do projektu.

Výpis 13.15: Definice třídy SequenceGenerator používající statickou inicializaci objektu.

Výpis 13.16: Definice finální třídy Person používající statickou metodu v konstruktoru objektu.

Výpis 13.17: Ukázka použití frameworku PowerMock pro statickou metodu.

Výpis 13.18: Definice konstruktoru třídy Person s využitím statické metody.

Výpis 13.19: Ukázka použití frameworku PowerMock pro finální třídu.

Výpis 14.1: Definice třídy Calculator s metodou pro součet vstupních hodnot

Výpis 14.2: Definice testovací třídy CalculatorTest.

Výpis 14.3: Metoda rate pro výpočet bonity klienta.

Výpis 14.4: Definice testovací třídy BonityRatingTest.

Výpis 15.1: Základní konfigurace Maven projektu pro testy ve frameworku Spring.

Výpis 15.2: Definice Spring bean ve třídě HelloService.

Výpis 15.3: Ukázka Spring testu pomocí anotace @SpringJUnitConfig.

Výpis 15.4: Ukázka Spring testu pomocí standardního rozšíření @ExtendWith.

Výpis 15.5: Základní konfigurace Maven projektu pro framework Spring Boot

Výpis 15.6: Konfigurace Spring Boot aplikace.

Výpis 15.7: Definice entity City.

Výpis 15.8: Definice JPA repository ve třídě CityRepository.

Výpis 15.9: Zadání struktury a dat databáze v souboru db.changelog-master.yaml.

Výpis 15.10: Ukázka integračního testu pomocí technologie JDBC.

Výpis 15.11: Ukázka integračního testu na třídu CityRepository.

Výpis 15.12: Definice servisní třídy CityService.

Výpis 15.13: Ukázka integračního testu na třídu CityService.

Výpis 15.14: Definice REST služby ve třídě CityController.

Výpis 15.15: Ukázka testu ControllerBeanTest na třídu CityController.

Výpis 15.16: Ukázka testu ControllerRestTest na RESTful službu.

Výpis 15.17: Konfigurace Maven projektu pro nástroj Spring REST Docs.

Výpis 15.18: Ukázka testu ControllerRestDocsTest na RESTful službu – část 1.

Výpis 15.19: Ukázka testu ControllerRestDocsTest na RESTful službu.

Výpis 15.20: Ukázka vygenerovaného souboru http-request.adoc.

Výpis 15.21: Ukázka vygenerovaného souboru response-fields.adoc.

Výpis 15.22: Konfigurace Maven projektu pro nástroj AsciiDoctor

Výpis 15.23: Předpis pro generování dokumentace v souboru api-guide.adoc.

Výpis 16.1: Maven závislosti pro nástroj Cucumber

Výpis 16.2: Implementace jednoduchého kalkulátoru ve třídě SimpleCalculator.

Výpis 16.3: Zadání jednoduchého kalkulátoru v souboru CalcSimple.feature.

Výpis 16.4: Implementace testu ve třídě SimpleCalcStepdefs.

Výpis 16.5: Implementace JUnit testu pro Cucumber

Výpis 16.6: Implementace kalkulátoru ve třídě AdvancedCalulator.

Výpis 16.7: Zadání rozšířeného kalkulátoru v souboru CalcAdvanced.feature.

Výpis 16.8: Implementace testu ve třídě AdvancedCalcStepdefs.

Výpis A.1: Ukázka řešení testu s parametry v JU4.

Výpis A.2: Ukázka testu na definovanou Spring Bean v JU4.

Výpis A.3: Ukázka čtení jména testovací metody v JU4 (pomocí pravidla @Rule)

Seznam obrázků

Obrázek 1.1: Diagram růstu nákladů na opravu nalezené chyby v čase.

Obrázek 10.1: Prezentace výsledku běhu testovací třídy BasicTests v nástroji Eclipse.

Obrázek 10.2: Schéma dekompozice JUnit 5 [40]

Obrázek 10.3: Schéma artefaktů JUnit 5 [41]

Obrázek 10.4: Schéma artefaktů JU5 a jejich vzájemné závislosti

Obrázek 11.1: Pořadí zpracování bodů rozšíření v JU5 (viz podkapitolu 5.11 v [28])

Obrázek 12.1: Seznam vytvořených a spuštěných testů z běhu deterministického generování testů.

Obrázek 12.2: Seznam vytvořených a spuštěných testů z běhu nedeterministického generování testů.

Obrázek 13.1: Schéma komponent pro komponentu Person..

Obrázek 13.2: Schéma komunikace komponent s použitím mock-objektu.

Obrázek 13.3: Schéma komunikace komponent s použitím stub-objektu.

Obrázek 13.4: Schéma komunikace komponent s použitím spy objektu.

Obrázek 14.1: Ukázka výstupu nástroje Cobertura v Jenkins [59]

Obrázek 15.1: Generátor Spring Boot projektů.

Obrázek 15.2: Přehled nástrojů pro dokumentaci RESTful služeb [58]

Obrázek 15.3: Ukázka připravených vstupních dat (tzv. snippet) v nástroji Eclipse.

Obrázek 15.4: Ukázka vygenerované dokumentace pro REST API ve formátu HTML.

Obrázek 16.1: Význam syntaxe Gherkin [10]

Obrázek 16.2: Výsledek běhu testovací třídy RunCukestest.

Obrázek 16.1: Hierarchie interfejsu Runner v JU4.

Obrázek B.1: Schéma dekompozice zdrojových kódů (vzorových příkladů použitých v knize)

Seznam tabulek

Tabulka 7.1: Předdefinované proměnné použitelné ve skriptech.

Tabulka 8.1: Implicitní převody typů, převzato z příručky JUnit User Guide [6]

Tabulka 10.1: Seznam možných stavů v anotaci @API

Tabulka 11.1: Seznam dostupných interfejsů pro body rozšíření

Tabulka 13.1: Srovnání jednotlivých druhů syntaxí pro konstrukci potvrzení

Tabulka 13.2: Výhody a nevýhody použití mock a stub řešení

Tabulka 13.3: Seznam referencí frameworku PowerMock.

Tabulka 15.1: Seznam běžně používaných metod Spring Rest Docs dokumentace.

Tabulka A.1: Krátký přehled posledních revizí hlavních verzí frameworku JUnit

Tabulka A.2: Pseudokořenový balíček a přehled ekvivalentních datových typů probraných ve druhé části

Tabulka A.3: Pseudokořenový balíček a přehled názvů metod ve verzi 3 a odpovídajících anotací ve verzi 5

Tabulka A.4: Mapování pokročilých funkcí JUnit 4 a JUnit 5.

Tabulka A.5: Seznam standardních pravidel JU4.

Tabulka B.1: Seznam technologií použitých ve zdrojových kódech (pro vzorové příklady)

Seznam odboček – podšeděných bloků

Jazyk Java versus platforma Java.

Odbočka – podšeděný blok.

Framework PowerMock.

Nástroj PIT.

Spring framework.

Framework Spring Boot

Framework Swagger.

Nástroj Cucumber.

Používané pojmy a zkratky

Zkratka

Termín

Význam

API

Application Programming Interface (Programové rozhraní aplikace)

Rozhraní, přes které mohou jiné programy s danou aplikací komunikovat.

Argument

Hodnota předávaná metodě v parametru označovaná někdy jako skutečný parametr (viz Parametr).

Black-box testing (Testování metodou černé skříňky)

Testování aplikace bez detailní znalosti její implementace. Testuje se pouze, zda testovaný objekt odpovídá na zadané podněty zadaným způsobem.

Callback

Volané metodě (resp. oslovenému objektu) je v parametru předán objekt, jehož prostřednictvím pak tato metoda nebo její vlastník komunikuje s volajícím objektem.

DAO

Data Access Object (Objekt pro přístup k datům)

Objekt poskytující abstraktní rozhraní k nějakému typu databáze nebo jinému mechanismu trvalého uložení dat.

DB

Databáze

Sada dat uložená prostřednictvím nějakého systému pro řízení báze dat (SŘDB) umožňujícího manipulaci s uloženými daty a přístup k nim. V praxi se termín databáze často (byť ne zcela správně) používá v širším smyslu zahrnujícím jak uložená data, tak i software (SŘBD).

DTO

Data Transfer Object (Přepravka)

Označení objektu sloužícího pro přenos dat mezi jednotlivými částmi aplikace (viz Přepravka).

Datovod

Instance některého z potomků interfejsu java.util.stream.BaseStream

DBMS

Database Management System

Viz SŘDB - Systém pro řízení báze dat.

Fluent API

API umožňující konstrukci objektu či výrazu plynulou a přirozenou cestou.

JU4

JUnit 4

Čtvrtá verze frameworku JUnit.

JU5

JUnit 5

Pátá verze frameworku JUnit.

IS

Informační systém (Information System)

Systém složený z hardwaru a softwaru sloužící nějakému účelu (např. ERP či CRM).

IDE

Integrated Development Environment (Integrované vývojové prostředí)

Program sdružující sadu nástrojů usnadňujících jednotlivé činnosti při vývoji programů (editace, překlad, ladění, refaktorace, tvorba testů, sestavování, správa verzí, řízení projektu, …).

Interface (rozhraní)

Signatura plus kontrakt, které musí implementace daného rozhraní dodržet. Své rozhraní má každá entita programu: balíček, třída, metoda, proměnná, …

Interface type (interfejs)

Programová konstrukce definující v jazyku Java datový typ reprezentující rozhraní.

IoC

Inversion of Control (Inverze řízení)

Návrhový vzor řešící problematiku vzájemné závislosti frameworku a komponent, které jej využívají.

Java EE

Java Enterprise Edition

Nadstavba standardní verze platformy Java (Java SE) určená pro tvorbu distribuovaných aplikací (aplikací běžících na několika spolupracujících počítačích) používaná např. v informačních systémech podniků.

JPA

Java Persistence API

Standard pro tvorbu perzistentní vrstvy pomocí objektově-relačního mapování (viz ORM).

JavaScript

Dynamický jazyk používaný pro tvorbu uživatelského rozhraní webových aplikací.

Jednotkové testování

Tvorba testů ověřujících funkcionalitu jednotek zdrojového kódu (metod, tříd, komponent, …).

JVM

Java Virtual Machine

Virtuální stroj Javy

Mockování

Vytváření mock-objektů, tj. falešných instancí dané třídy s definovaným výstupem pro definované vstupy.

Model rozšíření (Extension Model)

API pro rozšiřování funkčností a vlastností frameworku.

ORM

Object-relational mapping (Objektově relační mapování)

Technologie zajišťující automatickou konverzi dat mezi relačním modelem používaným v databázi a objektovým modelem používaným v programu.

Parametr

Proměnná, jejímž prostřednictvím předává volající program volané metodě potřebná data – argumenty.

Přepravka (Crate, Transfer Object)

Návrhový vzor doporučující jak definovat objekt sloužící k přenosu skupin dat mezi částmi aplikace.

Refactoring (Refaktorace kódu)

Úprava zdrojového kódu neměnící jeho funkcionalitu, ale zlepšující jeho architekturu.

REST

Representational state transfer

Architektura rozhraní, navržená pro distribuované prostředí.

Rozšíření (extension)

Možnost doplnění funkčnosti frameworku.

SLA

Service Level Agreement

Smlouva mezi poskytovatelem služby a uživatelem definující fungování požadované služby (dostupnost, výkon, počet uživatelů atd.).

Sestavení aplikace

Poskládání přeložených částí a dat do výsledného tvaru, např. do souboru (nebo sady souborů) typu JAR.

SW

Software

Aplikace či IS zajišťující nějakou funkčnost.

SŘDB

Systém pro řízení báze dat (Database Management System)

Sada programů umožňující přístup k datům uloženým v databázi a efektivní manipulaci s těmito daty.

TDD

Test Driven Development (Vývoj řízený testy)

Metodika vývoje požadující definici testů před zahájením implementace. Vlastní vývoj pak spočívá v úpravách programu vedoucích k úspěšnému projití daných testů.

Test Coverage (Pokrytí kódu testy)

Metrika udávající, jaké procento zdrojového kódu je pokryto existujícími testy.

Testovací scénář

Testovací scénář představuje návod, podle kterého se testuje daná funkcionalita.

UAT

Uživatelské akceptační testy (User Acceptance Test)

Testy používané při akceptaci díla, tj. při jeho přebírání zákazníkem, přičemž dílem může být jak nový program, tak pouze jeho dílčí změna.

UI

User Interface (Uživatelské rozhraní)

V kontextu této práce je jím myšleno webové rozhraní (HTML, JavaScript a CSS).

Unit testing

Viz Jednotkové testování

White-box testování (Testování metodou bílé/skleněné skříňky)

Testování entity se znalostí její implementace.

Předmluvy autorů

Rudolf Pecinovský

Kniha vznikla rozpracováním diplomové práce Arnošta Havelky ([21]), která se mi natolik líbila, že jsem mu nabídl, že bychom ji mohli po jistém přepracování zkusit společně nabídnout k vydání nakladatelství Grada.

V průběhu práce se však ukázalo, že Arnošt si rozumí spíše se zkušenějšími programátory a výklad pro začínající uživatele není jeho oblíbená parketa. Tak jsme se dohodli, že si text rozdělíme. Teoretický úvod převezmeme z jeho práce s tím, že jej na některých místech trochu upravím, aby mu porozuměli i nepříliš zkušení uživatelé. Druhou část určenou pro začínající uživatele napíšu já a další dvě části určené spíše pro ty zkušenější napíše on. Obdobně jsme si rozdělili i tvorbu přílohy pojednávající o testech vytvořených pro minulé verze frameworku a o možnostech jejich dalšího využívání. Tak vznikla kniha, kterou držíte v ruce.

Doprovodné programy a jejich prohlížení

Protože jsem text knihy i lámal, aby optimálně zaplnil stránky, měl bych pro vás ještě jednu informaci. Knihu jsem se snažil zalomit tak, aby všechny výpisy programů a komunikace s počítačem, které se vejdou na jednu stránku, byly vždy na jedné stránce, i když je občas bylo třeba kvůli tomu o stránku či dvě posunout. Čtenářům papírové verze by se tak měly minimalizovat problémy při studiu doprovodných textů diskutujících obsah těchto výpisů.

Čtenáři elektronické verze jsou na tom s listováním hůře. Těm bych doporučil, aby si text knihy otevřeli dvakrát a umístili oba dokumenty vedle sebe. (Na většině současných počítačů s širokými monitory by to neměl být problém.) Pak lze mít v jednom okně otevřenou stránku s výpisem a ve druhém stránku s rozborem obsahu daného výpisu a s případnými odkazy na jeho jednotlivé řádky.

Arnošt Havelka

Každá cesta někde začíná a končí, většinou však nebývá přímočará. Stejně to platí i pro knihu, kterou právě držíte v ruce. Její osud rozhodně nebyl přímočarý, místy musím přiznat i napínavý, zejména když se blížil termín uzávěrky. V každém případě si kniha našla cestu do vašich rukou, za což bych chtěl velmi poděkovat. Vážím si toho.

V této části samozřejmě nemůžu vynechat poděkování, které patří především mé rodině za nezměrnou trpělivost a podporu po celou dobu tvorby knihy. Velký dík samozřejmě patří také Rudolfovi, neboť bez jeho cenných rad a vedení by asi kniha nevznikla. Určitě by nevznikla v takové kvalitě, do jaké se nám ji společně podařilo dostat. Začátečnické nadšení a zápal je výborná věc, někdy však k úspěchu prostě nevede.

Závěrem svého úvodního slova bych rád ještě požádal o zpětnou vazbu, která je důležitá u každého díla (nejen u knihy). Pokud se vám kniha líbila, tak bych velmi ocenil udělení hvězdičky na adrese https://github.com/arnosthavelka/junit-poc, kde jsem připravoval všechny ukázkové příklady k frameworku JUnit. Pozitivní zpětná vazba mě může motivovat k další tvůrčí práci. Pokud máte jakékoliv konstruktivní připomínky či výhrady, tak neváhejte a vytvořte na výše uvedeném odkazu podnět (issue).

Úvod

Účel této publikace

Tato kniha by měla být rychlou úvodní příručkou soužící dvěma skupinám uživatelů. Její první a druhá část je koncipována tak, aby byla užitečná i pro programátory pracující na platformě Java, kteří prozatím nemají žádné zkušenosti s jednotkovým testováním. Přestože vám nepředvede všechny detaily jednotkového testování, pokusí se poskytnout vše, co potřebujete vědět, abyste se mohli ponořit do tvorby jednotkových testů vašich programů využívajících platformu JUnit 5, přesněji JUnit 5.3.1.

Současně jsme se snažili, aby tyto vstupní části přinesly potřebné informace i zkušenějším programátorům, kteří již s frameworkem JUnit pracují a potřebují se seznámit s novinkami, které přináší jeho pátá verze. Těm zkušenějším jsou navíc určeny i následující části. Třetí část probírá architekturu frameworku a seznamuje s jeho pokročilejšími funkcemi, čtvrtá část se zaměřuje na spolupráci frameworku s jinými aplikacemi a frameworky, které mohou jeho služeb využít a rozšířit jeho funkcionalitu.

Trocha historie

Framework JUnit představuje jedno z mnoha dostupných řešení pro tvorbu jednotkových testů. Je portem původního frameworku SUnit, který v roce 1989 vytvořil v jazyku Smalltalk a publikoval Kent Beck1. V roce 1997 letěl s Erichem Gammou2 z Zürichu na konferenci OOPSLA do Atlanty. V letadle se nudili, a tak převedli Beckovu knihovnu na platformu Java, jejíž popularita tehdy rychle rostla a stávala se postupně hlavním programovacím jazykem vstupních kurzů programování. Svůj výtvor nazvali JUnit.

Jazyk Java versus platforma Java

Když v roce 1995 představovala firma Sun jazyk a platformu Java, tak si její marketingové oddělení neuvědomilo, že pod stejným názvem představuje dva naprosto rozdílné produkty.

Použitý programovací jazyk určuje způsob vyjadřování vašich myšlenek. Použitá platforma specifikuje prostředí, v němž program napsaný v daném programovacím jazyku běží.

Řada komentátorů si tento rozdíl neuvědomuje dodnes a občas tyto pojmy dokonce zaměňuje. Když např. Microsoft na přelomu století propagoval chystanou platformu .NET, uváděl, že platforma Java nabízí pouze jeden programovací jazyk, kdežto oni uvedou svoji platformu se čtyřmi jazyky, jejichž sada se vbrzku rozroste o desítku dalších. Jenomže už v té době bylo na platformě Java možno použít přes 80 programovacích jazyků a v dnešní době jich je již několik set. Mezi nejznámější patří (dle abecedy) Clojure, Cobol, Fortran, Groovy, JavaScript, Kotlin, Lisp, Pascal, Perl, PHP, Prolog, Python, R, Ruby, Scheme či Visual Basic.

V textu knihy se proto budeme snažit důsledně rozlišovat, kdy hovoříme o platformě Java a kdy o stejnojmenném programovacím jazyku.

Na konferenci svůj čerstvý výtvor představili. Popularita jejich frameworku raketově rostla a zanedlouho bylo nemyslitelné, že by nějaké vývojové prostředí nemělo zabudovanou jeho podporu. Popularita tohoto frameworku inspirovala vývojáře pracující na jiných platformách (PHP, JavaScript, .NET, Python, …), aby framework převedli na svoji oblíbenou platformu, takže nyní se s jeho „sourozenci“ setkáte na všech jen trochu rozšířených platformách (wikipedie uvádí přes 80 portů).

Martin Fowler, známý počítačový guru, jednou charakterizoval význam tohoto frameworku parafrází známého Churchillova výroku o letecké bitvě o Anglii, když řekl: „Při vývoji softwaru ještě nikdy nevděčilo tolik lidí tak moc tak málo řádkům kódu.“3

První verze frameworku byly totiž opravdu malé. Jenomže každá další verze chce uživatelům umožnit, aby mohly spouštět i testy napsané pro minulou verzi, takže pak obsahuje minulou i novou verzi frameworku, takže framework pomalu bobtná.

Jak už jsme naznačili, framework se postupně vylepšoval. V současné době je nejrozšířenější verze 4, která se narodila v roce 2004 a do svého konceptu zapracovala generické datové typy a anotace zavedené v tehdy nové Javě 5.

Další výrazná změna přišla s verzí JUnit 5, jež se narodila v roce 2017 záhy po uvedení Javy 9, která zavedla moduly. Verze 5 se pomalu prosazuje, ale řada programátorů dává ze setrvačnosti přednost verzi předchozí (po těch letech si na ni už zvykli). Tato kniha by vás chtěla s novou verzí seznámit a ukázat vám její výhody a možnosti jejího použití v nejrůznějších vývojových nástrojích.

Terminologie

Jak už bylo řečeno, různé části knihy se snaží vyjít vstříc různým skupinám uživatelů. Tomu odpovídá i použitá terminologie.

V první a druhé části preferujeme standardní českou terminologii, protože je pro začátečníky srozumitelnější. Navíc zkušenost ukazuje, že si pak význam jednotlivých termínů dokáží snadněji zapamatovat.

Ve třetí a čtvrté části respektujeme, že zkušenější programátoři se většinou pohybují v prostředí zahlceném slangovými výrazy nebo dokonce v prostředí, kde spolu jednotliví spolupracovníci hovoří anglicky. Tito programátoři již často českou terminologii nepoužívají. Proto v těchto částech částečně rezignujeme na „správnou češtinu“ a dáváme přednost slangovým výrazům odvozeným z angličtiny.

Potřebné vybavení a doprovodné programy

Pro úspěšné studium této knihy potřebujete mít instalované vývojové prostředí, které vám umožní vyvíjet program nad platformou Java 8 nebo novější. Jak už jsme naznačili na začátku úvodu, nemusí to být nutně programy v jazyce Java, ale měly by to být programy běžící nad platformou Java.

Druhou věcí, kterou budete potřebovat, je framework JUnit verze 5, resp. některá z jeho následujících podverzí (v době vydání knihy to byla verze 5.3.0). Používáte-li některé z rozšířených profesionálních integrovaných vývojových prostředí (IDE), je velmi pravděpodobné, že už v něm bude tato verze frameworku zabudována.

K tomu, abyste mohli popisovaný framework plnohodnotně využívat, je vhodné se občas začíst do jeho programátorské dokumentace. Tu najdete na adrese https://junit.org/junit5/docs/current/api. O její off-line verzi použitelné i v případě, kdy nejste aktuálně připojeni k internetu, prozatím nevíme.

Další věcí, která by se vám mohla hodit, jsou doprovodné programy. Mezi nimi najdete všechny příklady uvedené v knize a navíc i několik dalších. Způsob jejich získání záleží na tom, ke které části knihy je potřebujete:

•V první části žádné doprovodné programy nejsou.

•Doprovodné programy k výkladu v druhé části určené pro programátory začínající s frameworkem JUnit 5 najdete na webové stránce knihy na adrese http://knihy.pecinovsky.cz/54_junit5.

Kromě doprovodných programů najdete na této stránce časem i výklad pasáží, které se již do knihy nevešly4, např. výklad některých návrhových vzorů. Bude-li potřeba, objeví se zde i errata a odpovědi na vaše případné dotazy.

•Popis získání doprovodných programů k výkladu ve třetí a čtvrté části určené pro zkušenější uživatele frameworku JUnit 5 je trochu složitější, a proto jsme jej umístili do přílohy Potřebné vybavení a programy pro třetí a čtvrtou část.

Použité typografické konvence

K tomu, abyste se v textu lépe vyznali (a také abyste si vykládanou látku lépe zapamatovali), používáme několik prostředků pro odlišení a zvýraznění textu.

Termíny

První výskyt nějakého termínu a další texty, které chci zvýraznit, vysazuji tučně.

Název

Názvy firem a jejich produktů vysazuji kurzivou. Kurzivou vysazuji také názvy kapitol, podkapitol a oddílů, na které se v textu odkazuji.

Odkaz

Celá kniha je prošpikovaná křížovými odkazy na související pasáže. Není-li odkazovaný objekt (kapitola, obrázek, výpis programu, …) na stejné stránce nebo na některé ze sousedních stránek, je pro čtenáře tištěné verze doplněn o číslo stránky, na níž se nachází. Čtenářům elektronické verze stačí, když na něj klepnou, a použitý prohlížeč by je měl na odkazovaný objekt ihned přenést.

Citace

Texty, které si můžete přečíst na displeji, např. názvy polí v dialogových oknech či názvy příkazů v nabídkách, vysazuji tučným bezpatkovým písmem.

Adresy

Názvy souborů a internetové adresy jsou vysazeny obyčejným bezpatkovým písmem.

Program

Identifikátory a další části programů zmíněné v běžném textu vysazuji neproporcionálním písmem, které je v elektronických verzích pro zvýraznění tmavě červené.

metoda(?)

Při odkazech na metody budu v závorkách za názvem metody vždy uvádět seznam typů jejich parametrů – např. equals(Object). Nebude-li v danou chvíli jasné, jaké má zmiňovaná metoda parametry, budu do závorek psát otazník – např. metoda(?).

zadání

Ve výpisech programů a odpovědí počítače budou části, které chceme zdůraznit, vysazeny tučně (v elektronických verzích pro zvýraznění tmavě červeně) a budou navíc i trochu jinak podbarveny.

Kromě výše zmíněných částí textu, které považujeme za důležité zvýraznit nebo alespoň odlišit od okolního textu, najdete v knize ještě řadu doplňujících poznámek a vysvětlivek. Všechny budou v jednotném rámečku, jenž bude označen ikonou charakterizující druh informace, kterou vám chce poznámka či vysvětlivka předat.

Symbol jing-jang bude uvozovat poznámky, s nimiž se setkáte na počátku každé kapitoly. Zde vám vždy prozradím, co se v dané kapitole naučíte.

Otevřená schránka s dopisy označuje informace o projektu, s nímž budeme v dalším textu pracovat, nebo v něm najdete vzorové řešení aplikující probranou látku.

Obrázek knihy označuje poznámku týkající se používané terminologie. Tato poznámka většinou upozorňuje na další používané termíny označující stejnou skutečnost nebo na konvence, které se k probírané problematice vztahují.

Brýle označují tzv. „poznámky pro šťouraly“, ve kterých se vás snažím seznámit s některými zajímavými vlastnostmi probírané konstrukce nebo upozorňuji na některé souvislosti, avšak které nejsou k pochopení látky nezbytné.

Píšící ruka označuje obyčejnou poznámku, která pouze doplňuje informace z hlavního proudu výkladu o nějakou zajímavost.

Ruka s hrozícím prstem upozorňuje na věci, které byste měli určitě vědět a na které byste si měli dát pozor, protože jejich zanedbání vás většinou dostane do problémů.

Mračoun upozorňuje na různá úskalí a radí, j ak s e t ěmto nástrahám v yhnout či jak to zařídit, aby vám alespoň pokud možno nevadily.

Odbočka – podšeděný blok

Občas je potřeba vysvětlit něco, co nezapadá přímo do okolního textu. V takových případech používáme podšeděný blok se silnou čarou po straně. Tento podšeděný blok je takovou drobnou odbočkou od ostatního výkladu. Nadpis podšeděného bloku pak najdete i v podrobném obsahu mezi nečíslovanými nadpisy.

Zpětná vazba

Přes veškeré úsilí, které jsme textu oba věnovali, nemůžeme vyloučit, že v textu či doprovodných příkladech zůstaly skryté chyby. Předem se za ně omlouváme. Objevíte-li v knize nějakou chybu nebo budete mít návrh na nějaké její vylepšení, neostýchejte se napsat na adresu rudolf@pecinovsky.cz. Pokusíme se co nejdříve zanést na stránku knihy příslušná errata s opravou, kterou pak zapracujeme do případného dalšího vydání.

Bude-li vám někde připadat text nepříliš srozumitelný nebo budete mít nějaký dotaz, ať už k vykládané látce či použitému frameworku, pošlete mail s předmětem DOTAZ_JUNIT_5. Bude-li se dotaz týkat něčeho obecnějšího, zveřejníme na stránce knihy http://knihy.pecinovsky.cz/49_adv_txt odpověď i pro ty ostatní, které by mohl obdobný dotaz napadnout za pár dní, anebo jsou natolik ostýchaví, že se netroufnou sami zeptat.

Část I: Teorie testování

První část knihy je věnována úvodnímu seznámení s teorií testování. Jde o relativní základy, bez ambicí nahrazovat jiné zdroje zabývající se teorií testování jako takovou. Cílem této části je uvést čtenáře do problematiky testování a poskytnout mu „nezbytné“ znalosti pro další výklad. Patří sem i představení celého rozsahu testování a nahlédnutí na testování z různých úhlů pohledu.

Uvedená teorie není k pochopení samotného frameworku JUnit nezbytná. Čtenář v ní však může nalézt řadu informací, na něž další kapitoly navazují.

Kapitola 1

Základy teorie testování

Co se vkapitole naučíte

Kapitola přiblíží význam aúčel testování aseznámí vás sklasifikací testů podle různých kritérií. Probere náklady na odstranění chyby vjednotlivých etapách životního procesu produktu, seznámí vás smetodikou vývoje řízeného testy, představí testovací frameworky používané vjednotlivých etapách vývoje aukáže pozici frameworku JUnit probíraného vtéto knize.

Množství dostupných apoužívaných technologií se neustále zvětšuje, čímž se vývoj softwaru stává velmi komplexní záležitostí. Neustálý rozvoj technologií apředevším požadavků kladených na kvalitu astabilitu vyvíjeného softwaru znamená, že je třeba se stále více soustředit na testování.

Základní cíl testování samozřejmě stále představuje minimalizace chyb, obecně však od testování požadujeme zvýšení kvality dodávaného softwaru. Důkazem tohoto trendu je fakt, že tvorba jednotkových testů se dnes považuje za běžnou součást vývoje softwaru apředstavuje de facto standard.

1.1Význam aúčel testování

Jak již bylo řečeno, vývoj softwaru je komplexní disciplína skládající se zmnoha různých kroků, od sběru požadavků přes návrh architektury, design programu, kódování, integraci jednotlivých součástí až po předání programu zákazníkům aprovozní podporu. Výsledek většiny uvedených kroků může být ověřován, tedy testován. Testování se tak přirozeně rozvinulo do samostatné disciplíny, ikdyž návrh testů pro kroky předcházející kódování je zatím vplenkách.

Tato kniha se soustřeďuje na ověření požadované funkčnosti programu, tedy funkčního kódu. Ztohoto pohledu je testováním myšleno ověření, zda chování programu odpovídá všem zadaným funkčním inefunkčním požadavkům.

1.2Klasifikace testů

Vývoj softwaru slučuje řadu disciplín, ve kterých se používá mnoho různých testů. Druhy testů lze klasifikovat podle metodiky testování, detailnosti znalosti problematiky (strategie testování), typu testů nebo způsobu testování.

Pro klasifikaci testů lze nalézt mnoho různých přístupů ametod. Základní klasifikace testů je pro účely této knihy definována za pomoci řady zdrojů (viz [65], [12] a[64]) asamozřejmě také na základě praktických zkušeností svývojem softwaru.

Metody testování

•Statické testování

představuje „pasivní“ testy, při nichž není program spuštěn. Při těchto testech se prochází avyhodnocuje zdrojový kód. Při tomto způsobu testování se využívá řada metod počínaje kontrolou kódu pověřenou osobou (code review nebo peer-review) až po využívání různých nástrojů pro statickou kontrolu kódu (PMD, Checkstyle, FindBugs, …).

Statické testování neslouží prvotně kotestování funkčnosti, ale knalezení míst spotenciálními (ačasto iskutečnými) chybami.

•Dynamické testování

představuje testování běžícího programu nebo jeho části, při kterém se ověřuje funkčnost testovaného softwaru podle předem připravených testovacích scénářů (jednotkových testů, integračních testů, akceptačních testů, …).

Strategie testování

•Black-box

znamená testování funkčnosti bez požadavku na znalost implementace, např. bez znalosti použitého programovacího jazyka, strukturování aplikace, používaných algoritmů apřístupů atd. Pouze se testuje, zda testovaný objekt poskytne po zadaném vstupu zadaný výstup (obecněji zda zadaný podnět vyvolá požadovanou reakci).

•White-box / Glass-box

představuje testování probíhající na základě znalosti vnitřní struktury. Při statickém testování dokonce ani jinou strategii použít nemůžeme.

Tento přístup je charakteristický pro jednotkové testy, kterým je věnována tato kniha. Chceme-li totiž dobře otestovat např. nějakou metodu, měli bychom prověřit všechny cesty, kudy může program při provádění dané metody běžet, aktomu je potřeba znát definici dané metody.

•Gray-box

si lze vpodstatě představit jako kombinací obou dříve uvedených přístupů. Jde opřechod mezi testováním typu black-box awhite-box. Testování podle této strategie lze popsat jako testování black-box (testy zpohledu uživatele), avšak sjistou znalostí vnitřních struktur afungování softwaru.

Typy testů

•Funkční testy

se používají pro ověření funkčních požadavků směřujících na konkrétní funkčnost softwaru, např. chování konkrétní webové služby, obrazovky nebo formuláře. Funkční testy můžeme dále rozdělit na:

oJednotkové testy (unit tests)

oIntegrační testy

oSystémové testy

•Nefunkční testy

oBezpečnostní testy (často také označované jako penetrační testy)

oVýkonnostní testy

oTesty instalace

•Uživatelské testy

Způsob testování

•Manuální testování

1.3Náklady chyb