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ě.

5 komentářů:

benzin řekl(a)...

Druha moznost je pouziti DataProvider. Hlavni rozdil je v tom, ze zatimco DataProvider vytvari pouze jedinou instanci testove tridy nad kterou spousti metody, tak Factory, vytvari pro kazdy test jednu instanci.

POZOR!!! protoze TestResult, ktery je pouzit pro vypis vysledku testu si drzi odkaz na instanci testu je nutne vsechny instancni promene po sobe mazat. Jinak se vam muze jednoduse stat ze vam nebude stacit pamet. A @Factory zravost testu jeste nasobi.

My sme nejrpve rozhodly pro pouziti @Factory, ale nasledne vzhledem ke zravosti a ze DataProvider se da dedit, kdezto staticka @Factory ne, presli k DataProvideru.

Jira řekl(a)...

O data providerech jsme psal v předcházejícím textu. To, že v případě použití factory, existuje více instancí téže třídy je zřejmé z příkladu. Pro každou sadu testovacích metod existuje pouze jedna instance třídy, takže v mém příkladu budou 4 instance třídy SquareTest.

Dále factory metoda nemusí být statická. Pokud bude umístěna v jiné třídě, která bude mít bezparametrický konstruktor.

Otázkou je, v jakém okamžiku je vhodné použít factory? Určitě to není v okamžiku, který je uveden (SquareTest). Výhodou factory je, že může vytvořit instance jakékoliv třídy. Takže výhodou je, pokud vytvářím testy v závislosti na externích datech, např. obsahu adresáře. Pak je vhodnou volbou factory.

Tom řekl(a)...

Pres @Factory asi neudelam test , jehoz vysledkem ma byt vyhozena vyjimka, nebo se pletu?

Jira řekl(a)...

Ale pomocí @Factory se nedělají test metody (testy), ale třídy obsahující test metody. Takže vyhazování výjimek není předmětem zájmu.

Koukám, že jsem to napsal pěkně zmatečně, takže asi udělám nějaké doplnění a ukážeme si složitější příklad, který bude mít větší vypovídací hodnotu.

Tom řekl(a)...

To by bylo moc pekne, diky :-)