Java na web XI. - Testování

Dnes se budeme věnovat takzvaným jednotkovým testům. Díky nim můžeme mít jistotu, že vše funguje jak má a vyhneme se „špinavé“ práci při ručním testování.

3.8.2013 00:00 | Petr Horáček | přečteno 9447×

V minulém díle jsme si pověděli něco o možnostech autentizace a autorizace. Dnes se budeme věnovat problematice, která sice není pro koncové uživatele přímo viditelná, přesto je ale velice důležitá, půjde o testování aplikace. Nepůjde ani tak o testování rychlosti nebo zátěže, ale o pouhé zjišťování faktu zda apliakce funguje jak má.

Unit testing

Unit testing, neboli testování jednotek, je proces, při kterém testujeme funkčnost co nejmenších částí (jednotek) aplikace (tedy metod apod.). Při správném používání nám unit testing zaručí přehled o funkčnosti aplikace a to bez nutnosti neustálého testování při úpravách kódu. O samotné testování se starají k tomu určené frameworky.

JUnit

JUnit je unit testing framework vytvořený pro jazyk Java. Usnadňuje testování širokou škálou připravených metod, v aktuální verzi 4 je navíc jeho syntaxe díky použití anotací skvěle přehledná a snadná na použití. Protože je JUnit široce rozšířený, je implementovaný do řady vývojových prostředí, a to včetně NetBeans. Domovská stránka projektu: http://junit.org/

JUnit testy mají podobu obyčejných tříd, mohou se zde nacházet různé metody, jenž pomocí anotací přiřadíme k jednotlivým procesům testování. Zde je základní schéma třídy testu:

import org.junit.*;
 
public class Test {
    @BeforeClass
    public static void setUpClass() throws Exception {
        // Kód který se vykoná ještě před prvním testem,
        // pokud testujete metody jedné třídy, je ji zde
        // vhodné initializovat, pokud testujete databázi,
        // je zde to pravé místo pro navázání spojení atd.      
    }
 
    @Before
    public void setUp() throws Exception {
        // Kód který se vykoná před každým testem
    }
 
    @Test
    public void prvniTest() {
        // První kód testování
    }
 
    @Test(Timeout = 100)
    public void druhyTest() {
        // Druhý kód testování, selže, pokud neskončí do 100 ms    
    }

    @Test(expected = Exteption.class)
    public void tretiTest() {
        // Třetí kód testování, selže, pokud neskončí určenou vyjímkou    
    } 

    @Ignore
    @Test
    public void ignorovanyTest() {
        // Ignorovaný kód, nebude do testování zahrnut
    }
 
    @After
    public void tearDown() throws Exception {
        // Kód který se vykoná po každém testu 
    }
 
    @AfterClass
    public static void tearDownClass() throws Exception {
        // Kód který se vykoná po posledním textu
    }
}

Pozn.: Ve verzi JUnit 4.10 (která je součástí aktuálního NetBeans) jsou metody označené anotací @Test vykonávány asynchronně, jejich pořadí v kódu tedy nemá význam a nelze počítat s jejich postupným plněním.

Pozn. 2: Pokud přesto chcete udržovat přesné pořadí testů, můžete ze stránek JUnit stáhnout aktuální verzi 4.11 a vložit ji do projektu, poté stačí třídě testů přidat anotaci @FixMethodOrder. Tento postup ale není vhodný, testy by na sobě neměly být závislé.

Pro vyhodnocování průběhu testů se používají tzv. assert statements. Pomocí těchto metod můžete porovnávat očekávané výsledky s reálnými. Zde jsou vypsané některé z nich:

assertTrue(zprava, stav);
// kontroluje, zda je předaná boolean proměnná True,
// pokud ne, test neuspěje a předá danou zprávu

assertEquals(zprava, ocekavane, ziskane);
// porovnává hodnotu očekávanou se získanou

assertEquals(zprava, ocekavane, ziskane, tolerance);
// porovnává dvě float či double proměnné, tolerance
// udává možnou odchylku

assertNull(zprava, objekt);
// kontroluje zda je objektu null

assertNotNull(zprava, objekt);
// kontroluje zda objekt není null

assertSame(zprava, ocekavane, ziskane);
// kontroluje zda obě proměnné odkazují na stejný objekt

assertNotSame(zprava, ocekavane, ziskane);
//kontroluje zda obě proměnné odkazují na jiné objekty

Jednoduchý příklad celého testu, po jeho vykonání se vrátí hlášení o neúspěchu:

package testy;

import org.junit.Test;
import static org.junit.Assert.*;

public class TestPoctu {
    @Test
    public void testSouctu() {
        int int1 = 1;
        int int2 = 1;
        int int3 = 3;   
        assertEquals("Součet nesouhlasí", int3, int1 + int2);
    }
}

JWebUnit

JWebUnit je framework rozšiřující JUnit (to mimo jiné usnadňuje jeho použití ve vývojových prostředích). Usnadňuje testování webových aplikací, konkrétně jejich uživatelského prostředí. Díky JWebUnit můžete kontrolovat funkčnost formulářů, tabulek či prostých odkazů. Domovská stránka projektu: http://jwebunit.sourceforge.net/

Tento framework je v podstatě rozšíření JUnit v podobě několika balíčků. Stačí tedy vložit příslušné knihovny JWebUnit do projektu a používat jejich funkce v testech. Zde je několik příkladů použití přejatých z oficiální dokumentace:

/* 
    NAVIGACE
*/

setBaseUrl("http://localhost:8080/aplikace");
// nastaví kořenovou adresu aplikace

beginAt("index.jsp");
// začne prohlížení na adrese http://localhost:8080/aplikace/index.jsp

assertTitleEquals("Úvod");
// testuje přítomnost titulku

assertLinkPresent("prihlasit");
// testuje přítomnost odkazu s určenou ID

clickLink("prihlasit");
// stiskne odkaz s určeným ID

assertLinkNotPresent("prihlasit");
// testuje nepřítomnost odkazu

assertLinkPresentWithText("Přihlásit se");
// testuje přítomnost odkazu s textem

clickLinkWithText("Přihlásit se");
// stiskne odkaz s určeným textem

assertTextPresent("Vítáme vás na naší stránce");
// testuje přítomnost textu na stránce

assertElementPresent("uvitani");
// testuje přítomnost objektu na stránce podle jeho ID

assertTextInElement("uvitani", "Vítame vás na naší stránce");
// testuje přítomnost textu v objektu s určenou ID

/*
    PRÁCE S FORMULÁŘI
*/

assertFormPresent("vzkaznik");
// testuje přítomnost formuláře

assertFormElementPresent("vzkaz");
// testuje přítomnost vstupu formuláře

setTextFileld("vzkaz", "Ahoj");
// vyplní vstup

assertFormElementEqueals("vzkat", "Ahoj")
// testuje vyplnění vstupu

submit()
// odešle formulář

setWorkingForm("id_formulare")
// specifikuje formulář pro práci

assertButtonPresent("id_tlacitka")
// testuje přítomnost tlačítka

clickButton("id_tlacitka")
// stiskne tlačítko

/*
    PRÁCE S TABULKAMI
*/

assertTablePresent("id_tabulky");
// testuje přítomnost tabulky

assertTextInTable("id_tabulky", "Hrušky");
// testuje přítomnost řetězce v tabulce

assertTextInTable("id_tabulky",
                   new String[] {"Jablka", "Hrušky"});
// testuje přítomnost skupiny řetězců v tabulce

assertTableEquals("id_tabulky",
                   new String[][] {{"Jablka", "6"},
                                   {"Hrušky", "3"}});
// testuje obsah tabulky

A zde je příklad jednoduchého testu s použitím JWebUnit:

import org.junit.*;

import static net.sourceforge.jwebunit.junit.JWebUnit.*;

public class PrikladTestu {

    @Before
    public void prepare() {
        setBaseUrl("http://localhost:8080/aplikace");
    }

    @Test
    public void test1() {
        beginAt("/");
        assertTitleEquals("Vzkazník");
        setTextField("vzkaz", "Ahoj");       
        submit();        
    }
}

Testování

Nyní už přejděme k praxi. Budeme využívat funkcionalit NetBeans a jako pokusný projekt využijeme naší aplikace (text ale jistě bude mít přínos pro uživatele jiných prostředí a programátory jiných aplikací). V našem případě vytvoříme jeden test webového rozhraní, ve kterém vyzkoušíme přihlášení, přidání zápisku a jeho následovné smazání.

Příprava projektu

Nejprve bude třeba vytvořit nový adresář pro třídy obsahující jednotlivé testy a importovat knihovny JUnit, NetBeans se naštěstí skoro o vše postará.

Otevřete tedy projekt s aplikací, v levém bloku klikněte pravým tlačítkem na jeho položku a zvolte Propreties, mělo by se otevřít nastavení. V kartě Sources u položky Test package zvolte Add Folder, ve složce projektu vytvořte novou složku s názvem „test“ a vyberte ji. Label složky změňte na „Test Packages“ a potvrďte. Nyní by se ve stromu projektu měly objevit dvě nové položky: První s názvem Test Packages, do ní budeme vkládat všechny třídy spojené s testováním a oddělíme je tak od zbytku aplikace. Druhá s názvem Test Libraries do které budeme vkládat knihovny unit testing frameworků.

Nastavení projektu

Import knihoven

Knihovny JUnit se importují automaticky po přidání prvního testu, JWebUnit však musíme přidat ručně. Stáhněte tedy archiv z adresy http://sourceforge.net/projects/jwebunit/files/ a rozbalte jej do jakékoliv složky, ve které si uschováváte stažené knihovny (při importu do projektu se na ně pouze vytvoří odkaz, nepřekopírují se). Já pro tento účel vytvořil novou složku v adresáři projektu.

Nyní klikněte pravým tlačítkem na položku Test Libraries a přidejte nejdříve stažené knihovny jwebunit-core-xxx.jar, jwebunit-htmluni-plugin-xxx.jar a poté všechny knihovny ze složky lib.

Úprava databáze

Jak již bylo řečeno, budeme testovat přihlášení a přidání zápisku. Pro tento účel si vytvoříme testovacího uživatele. Připojte se tedy k dabázi a odešlete tento příkaz pro vytvoření uživatele „test“ s heslem „heslo“.

INSERT INTO JNW.users VALUES ("test", "955db0b81ef1989b4a4dfeae8061a9a6");
INSERT INTO JNW.user_roles VALUES ("test", "user");

Úprava zapisky.jsp

Abychom mohli kontrolovat úspěšnost přihlášení, potřebujeme identifikovat stránku s výpisem zápisků. Upravme trochu view zapisky.jsp, přidejte do tagu form prvního formuláře tento kód:

id="pridat-zapisek"

Vytvoření testu

Klikněte pravým tlačítkem na položku Test Packages a přidejte nový Java package s názvem testy. Do vytvořeného balíčku přidejte nový JUnit Test. V průvodci vytvořením zadejte název třídy WebTest, z dolních check boxů odškrtněte pouze Test Initializer, pro vygenerování metody s anotací @Before. Po potvrzení přidání ještě vyberte verzi JUnit 4.x. Všimněte si, že po přidání této třídy přibyl pod položku Test Packages balíček JUnit.

Nejprve přidejte import knihovny JWebUnit:

import static net.sourceforge.jwebunit.junit.JWebUnit.*;

Poté do třídy přidáme dvě proměnné uschovávající jméno a heslo testovacího uživatele. Vepište tedy do třídy mimo metody toto:

static private String uzivatel = "test";
static private String heslo = "heslo";

Dalším krokem bude nastavení adresy testování a přihlášení (to musíme dát buď do metody označené anotací @Before, nebo do testu společně s přidáním zápisku, protože se testy spouští asynchronně, nelze je řadit za sebe). Vygenerovanou metodu s anotací @Before přejmenujte na prihlaseniTest a přidejte do ní tento kód:

setBaseUrl("http://localhost:8080/JavaNaWeb");
beginAt("/");
assertTitleEquals("Zápisky");
setTextField("j_username", uzivatel);
setTextField("j_password", heslo);
submit();
assertElementPresent("pridat-zapisek");

Nejprve nastavíme základní adresu aplikace, poté se přesuneme se do jejího kořene. Následuje kontrola titulku, vyplnění formulářů a odeslání. Nakonec zkontrolujeme zda se přihlášení vydařilo.

Teď už vytvoříme novou metodu s testem přidání a smazání zápisku:

@Test
public void novySmazatTest() {       
    assertElementPresent("pridat-zapisek");
    setWorkingForm("pridat-zapisek");
    setTextField("nadpis", "nadpisTest");
    setTextField("obsah", "obsahTest");
    submit();
    assertTextPresent("nadpisTest");
    assertTextPresent("obsahTest");       
    submit("", "Smazat");
    assertTextNotPresent("nadpisTest");
    assertTextNotPresent("obsahTest");        
}

Nejprve zkontrolujeme, zda se nacházíme na stránce s výpisem zápisků. Dále nastavíme formulář pro práci, vyplníme textová pole a odešleme. Zkontrolujeme zda se nový zápisek nachází na stránce a následovně jej smažeme. Nakonec zkontrolujeme zda zápisek zmizel.

To je k našemu malému testu všechno, pro představu by to mělo stačit. Pokud chcete, můžete si vytvořit testy i na zbývající funkcionality aplikace.

Spuštění testu

Teď už zbývá jen vytvořený test spustit, protože jsme ale přidali do aplikace nové třídy a knihovny, musíme ji znovu sestavit, klikněte pravým tlačítkem na položku aplikace a zvolte Deploy. Z důvodu použití webového rozhraní v testu, je ještě potřeba spustit server. Přejděte do karty Services, rozklikněte položku Servers, klikněte pravým tlačítkem na Apache Tomcat a zvolte Start.

Pro spuštění testu existuje hned několik cest: Můžete z nabídky Run spustit všechny testy v projektu (Test Project) nebo pouze samotný test (Test File). Další možností je kliknout na položku projektu a zvolit Test či kliknout přímo na soubor testu a zvolit Test File. Spusťte tedy libovolným způsobem test WebTest.

V prostředí by se měl objevit nový blok Test Results s ohlášením o úspěšném provedení.

Výsledky testování

Každý test se otevře ve vlastní záložce. Na výpisu se nachází seznam všech testů ve třídě. Nad výpisem je zobrazena procentuální úspěšnost testu (pokud se podaří 1 ze 2 → 50 %). Tlačítky vlevo lze spustit testy znovu (všechny nebo pouze nezdařené).

Tip: Pokud chcete mít tlačítko pro spuštění testů po ruce, klikněte pravým tlačítkem na horní lištu s ikonami, zvolte Customize a přetáhněte do lišty tlačítka Test Project a Test File.

Závěr

To je pro dnešek vše. V příštím díle se budeme věnovat debuggování, logování, sledování protokolu a dalším věcem, které nám usnadní vývoj a nasazení aplikace.

Zdrojové kódy aplikace naleznete na GitHubu: https://github.com/PetrHoracek/JavaNaWeb

Online verze článku: http://www.linuxsoft.cz/article.php?id_article=1988