Zobrazují se příspěvky se štítkemtestování. Zobrazit všechny příspěvky
Zobrazují se příspěvky se štítkemtestování. Zobrazit všechny příspěvky

17. ledna 2009

Parametrizované testy v TestNG

Jak už jsem psal dříve, jako testovací framework používáme TestNG. A protože jsem se konečně dostal ke knize Next Generation Java Testing: TestNG and Advanced Concepts od autora TestNG, Cédrica Beusta, mohu se s vámi podělit o novinky, které jsem načerpal (každopádně ta kniha stojí za přečtení, zabývá se totiž nejen unitovým testováním).

Jak jsem již naznačil v minulém textu, hlavní výhodou, kterou vidím, jsou data providery. Proč se tedy tento článek nejmenuje data providery v TestNG? Protože jsem se dozvěděl i o jiné možnosti parametrizace testů v TestNG. Jedná se o factories (český název továrny mi nepřijde tak jasný), které jsou podobné parametrům v jUnitu 4. Takže jak to funguje (příklad je lepší než 1000 slov, opráším příklad z minulého článku):


public class SquareTest {

private Calculator calculator = new Calculator();
private int param;
private int result;

@Factory
public static Object[] create() {
return new Object[] { new SquareTest(0, 0),
new SquareTest(1, 1), new SquareTest(2, 4), new SquareTest(4, 16) };
}

public SquareTest(int param, int result) {
this.param = param;
this.result = result;
}

@Test
public void square() {
calculator.square(param);
assertEquals(result, calculator.getResult());
}

}
Na první pohled je rozdíl oproti jUnit velmi malý (pomineme-li míň anotací a jejich jiná jména). Nevracíme paramtery, ale již vytvořené instance tříd. Jaká je v tom výhoda? Factory metoda může vracet instance jakýchkoliv tříd, nejenom té ve které je definovaná. Tyto třídy mohou obsahovat nejenom testovací metody (označené anotací @Test) a i factory metody. Je to o hodně flexibilnější.

A proč TestNG podporuje jak factory metody tak data providery, když de facto realizují totéž? Protože pokud parametry využijeme u většiny testovacích metod v třídě, je pohodlnější je předat pomocí konstruktoru z factory metody. Data providery se hodí, pokud potřebujeme více skupin dat pro různé testovací metody. A samozřejmě nic nám nebrání obě věci kombinovat.

Na závěr jsem si nechal dotažení konceptu data provideru k dokonalosti. Co když chceme zavolat testovací metodu hodně krát, opravdu hodně hodně moc krát. Pak asi není ideální vytvořit všechny parametry dopředu, vložit je do dvourozměrného pole a vrátit z data provideru, to zblajzne moc paměti. Jak tedy na to? Data provider bude místo Object[][] vracet Iterator, jehož metoda next() vrátí jednorozměrné pole s hodnotami parametrů.

Pokud jsem vás stále nepřesvědčil, že TestNG stojí za zkoušku, pak to jistě zkusím zase příště.

1. prosince 2008

Lze testovat aplikaci, která s tím nepočítá

Motivací pro dnešní psaní je 28 czpodcast. Takže zpět k titulku, jde to, ale težko a to je ten problém. Ať už je to metoda, třída, modul nebo celá aplikace, vše musí být navrženo a naimplementováno s ohledem na testovatelnost.

A teď k jádru pudla. Testovatelnost UI je skoro to nejhorší. Ať je to UI webové, swingové a nebo nějaké jiné. Proč? Protože se mění. Většina změn aplikace se projeví v jeho uživatelském rozhraní. Proto se testy musí neustále měnit a modifikovat. Takže není ani tak problém v tom testy napsat, ale udržovat.

Dá se z této situace nějak vybruslit? Nedá, ale dá se řada věcí eliminovat. Tím co se eliminovat dá, je skutečnost, že se rozložení prvků v uživatelském rozhraní mění. Dojde-li k takové změně, pak špatně napsaný test prvek nenajde a nebo najde špatný prvek. Je nutno prvky UI identifikovat spíš než podle umístění (ať fyzického nebo logického) identifikovat podle nějakého logického jména. Tj. ve swingu musíme komponentám dávat jména a v HTML musíme tagům, které pro nás symbolizují komponenty, dávat speciální hodnoty atributům (id nebo class, ale i jiné), tak abychom je v kódu stránky dokázali jednoduše najít.

Pak i když s komponentami trochu hneme, tak nám to nevadí, protože podle tohoto logického názvu je vždy spolehlivě v okně nebo stránce najdeme.

Takže jako musíme komponentu napsat tak, abychom ji byli schopni otestovat, musíme i UI napsat, tak abychom jej otestovali. Rozhodně si tím ušetříme spoustu času a kolikrát si testování de facto umožníme.

9. června 2008

On se ještě používá jUnit? Vždyť máme TestNG.

Konečně jsem si poslechl záznam přednášky Jana Novotného Automatické testování v praxi. Jen více takových ...

Ale proč píšu tento příspěvek? Stále mě překvapuje jak velké množství lidí neustále používá jUnit, který mi přijde v porovnání s TestNG jak chudý příbuzný. Proto jsem se rozhodl nastínit 2 hlavní výhody TestNG, alespoň z mého pohledu.

Přecházel jsem na TestNG v době, kdy po jUnit4 nebylo ani vidu ani slechu, takže jsem měl rozhodování o hodně jednodušší. Ale i po uvolnění jUnit4 je TestNG lepší. Ovšem jako jUnit4 vyžaduje Javu 1.5, takže pro vás co běžíte na Javě 1.4 a méně, pak máte smůlu (ovšem testy můžete překládat jinou verzí Javy než produkční kód).

Na úvod porovnání uvedu: jako vývojové nástroje používám Eclipse, builduji Antem nebo Mavenem a necítím se být nijak limitován užíváním TestNG oproti jUnitu.

Nyní k výhodám. Hlavní skutečnost, která mě hnala za změnou jUnitu za něco jiného je skutečnost, kterou se sice podařilo vyřešit, ale neskutečmě se mi nelíbila. Jde o to, že každý test nejenom dostává vlastní novou instanci TestCaseu, ale tato instance je zároveň použita jako objekt nesoucí informaci o výsledku testu (proběhl / neproběhl). Proč mi to vadí? Protože pokud máte hodně testů a u hodně z nich si naplníte instanční proměnné nějakými instancemi, pak vám běh testů sežere hodně paměti (protože se instance TestCaseů neuvolní pro garbage collection), pokud nespadnou na nedostatek paměti. Takže buď musíte ručně nastavovat hodnotu null do všech instančních proměnných (pracné a náročné na nezapomenutí) a nebo mít připraveného předka, který bude mít tearDown s funkcí nastavování hodnoty null instančním proměnným.

Druhou obrovskou výhodou, kterou jsem dokázal ocenit až po chvíli užívání testNG jsou data-providery. jUnit4 nabízí něco podobného v podobě parametrizovaných testů, ovšem to co nabízí TestNG se to podobá hodně vzdáleně. Když se podíváme na příklad z článku o jUnit4 na devx.com:

@RunWith(Parameterized.class)
public class SquareTest {

private static Calculator calculator = new Calculator();
private int param;
private int result;

@Parameters
public static Collection data() {
return Arrays.asList(new Object[][]{ {0, 0}, {1, 1}, {2, 4}, {4, 16} });
}

public SquareTest(int param, int result) {
this.param = param;
this.result = result;
}

@Test
public void square() {
calculator.square(param);
assertEquals(result, calculator.getResult());
}

}
Z příkladu je zřejmé, že jUnit parametrizuje na úrovní třídy, protože parametry se ze statické metody předávají do konstruktoru třídy. Naproti tomu TestNG:
public class SquareTest {

private Calculator calculator = new Calculator();

@DataParameter(name = "square")
protected Object[][] data() {
return new Object[][]{ {0, 0}, {1, 1}, {2, 4}, {4, 16} };
}

@Test(dataProvider = "square")
public void square(int param, int result) {
calculator.square(param);
assertEquals(calculator.getResult(), result);
}

}
Data providerů můžu mít v TestNG víc, dokonce může data provider být z jiné třídy, než test, který jej využívá. Jediné, co si mi nelíbilo, je přehození parametrů metod assert, tj. první je actual a druhý expected. Naštěstí existuje třída AssertJUnit, která zachovává zvyklost z jUnitu.

Tyto dvě skutečnosti jsou pro mě tak silnými argumety, že jsem přešel a nelituji. Navíc použití data providerů je tak jednoduché, že dnes je používám možná více než je zdrávo, ale když jsou tak elegantní.

25. května 2008

Test prošel. To je špatně!

Test Driven Development má jednu obrovskou výhodu. Tj. napsat test na neexistující funkcionalitu, pustit jej a ... ano správně ověřit, že test neprošel. Co je to za výhodu?

Přiznám se, že TDD stále není můj šálek kávy. Jestli jsem moc starej a nebo jsem ještě nevyspěl, nevím. Ale stále píšu kód a ten pak testuju a ne obráceně. Stále je moje myšlení tam, že vymýšlím jak věc udělat, když ji tvořím a ne, když vymýšlím test.

No a tady je zakopanej pes, protože pokud chci být korektní, musím manuálně a naprosto proti směru vývoje věcí, nakonec kus kódu pozměnit a zjistit, zda se nestane to co inzeruju v nadpise.

Pokud totiž tento krok neudělám, pak se může stát co se mi už nejednou stalo a to, že testy prošli, ale ne proto, že jsem měl dobře napsanej kód, ale protože test netestoval to co měl.

Stále se přesvědčuji, že Extreme Programming je domyšlené do posledního puntíku a je jenom otázkou času, než to zjistím.

15. května 2008

Na unit testy si vždy čas udělám ...

Přečetl jsem si příspěvek Máte čas na unit testy? od Petra Jůzy a po dlouhé době, mě nějaký text přiměl k reakci (Kde je dagi se svými kontroverzními tematy).

Přiznám se, že s testováním jsem začínal nějakým 8 let zpátky za pomocí jUnit knihovny a měl jsem dobrý pocit. Spíš mě to ale zdržovalo. Postupem času jsem se naučil (alespoň si to myslím) testy psát, začal jsem používat Coberturu a přešel jsem na TestNG.

Nedokážu si představit, že bych neměl unit testy. Proč? Jak píšu kód, píšu testy, kterými ověřím, že to celé funguje ještě předtím, než začnu integrovat komponenty dohromady. Jak to dělají ti, co testy nepíšou netuším. Pokud si vše otestuju, pak v návazných objektech používám mock implementaci téhož (díky EasyMock knihovně) a testuju dál. Nejednou jsem kód měnil, abych ho dokázal otestovat a nejednou jsem se setkal s tím, že se mi taková změna v budoucnu vyplatila.

Psát testy stojí čas, ale i když testy nepíšete, nějak musíte testovat a to také stojí čas. Pokud dojde na nějaké úpravy v budoucnu, pak jsou testy k nezaplacení, protože vzpomenout si, jak jsem to vlastně před půl rokem testoval, to už chce sakra dobrou paměť. Při opravě chyb je to podobné, testy opět pomůžou.

Psát testy až po odladění aplikace je zvěrstvo a plýtvání časem. Má to význam pouze pokud chceme opravit chybu nebo udělat změnu. Pak se může vyplatit napsat na ni testy a teprve poté se pustit do změn.

Nepoužívám TDD a tudíž testy píšu až po napsání výkonného kódu. Nějak na tuto myšlenku nejsem ještě připraven.

A co my testy přinášejí především? Jistotu ...