Archiv pro štítek: TestNG

Jak na Selenium testy pro CzechIdM

V tomto článku si ukážeme, jak zprovoznit Selenium testy pro CzechIdM a napsat svůj první test. Předpokládá se, že máte k dispozici vývojové prostředí pro CzechIdM s TestNG (pokud ne, začněte naříklad zde).

Požadavky

Zde uvádím seznam potřebného softwaru, včetně verze, se kterou jsem pracoval, pro referenci, kdyby v budoucnu došlo k nekompatibilitě.

  • naklonované CzechIdM z repozitáře, Java 1.7
  • TestNG (pokud používáte Eclipse, nejlépe jako plugin)
  • Selenium Client & WebDriver Language Bindings pro Javu (testováno s verzí 2.44)

nepovinné, ale ušetří čas:

  • Selenium IDE (testován plugin pro firefox verze 2.8.0)

Příprava Selenium v Eclipse

Rozbalíme Selenium Client & WebDriver Language Bindings, v něm se nacházi několik .jar souborů (v aktuální verzi 2) a složka libs ve které jsou další (v aktuální verzi 37). V Eclipse klikneme pravým na projekt czechidm-test a vybreme Properties. Na Záložce Java Build Path v podzáložce Libraries je tlačítko Add External Jars …, Přidáme tedy všechny knihovny (aktuálně 39). Nyní by měly Selenium testy v pořádku proběhnout.

První test se Selenium IDE

Po instalaci pluginu a restartu prohlížeče se vpravo od adresního řádku objeví logo Selenium IDE, tím ho spustíme. Base URL zadáváme bez idm/, pokud testujete na lokálním počítači s testovacím prostředím nastaveným podle návodu na tomto blogu, je to nejpravděpodobněji http://localhost:8080/. Vpravo pod řádkem pro Base URL je červené tlačítko pro nahrávání. Otevřeme si tedy IdM, nastavíme Base URL a začneme nahrávat.

Base URL a nahravani

Pokud budete testů dělat více a nebudete chtít, aby se pokaždé znovu přihlašovaly, je potřeba si ohlídat jejich pořadí, pro začátek však uděláme test co se přihlásí i odhlásí.

V tomto vzorovém testu se tedy přihlásíme do IdM, otevřeme záložku Reports, do kolonky Executor napíšeme admin a klikneme na Search. Nakonec se odhlásíme.

Nahravani testu

V tuto chvíli v okně Selenium IDE máme nahranou kostru prvního testu. Můžeme si ho pro jistotu spustit a dát se do úprav. Samotné Selenium IDE nám nabízí spoustu nástrojů pro kontrolu (ne)existence obsahu, ale jsou věci (například právě obsah tabulky vyčtené z databáze), které je praktičtější napsat rovnou v Javě, než v samotném Selemium IDE.

Podívejte se však jaké možnosti Selenium IDE nabízí. Stačí kliknout pravým tlačítkem na řádek, před který chceme přidat kontrolu a kliknout na Insert New Command. V kolonce Command vybereme nebo napíšeme příkaz, Target je cílový element a Value hodnota (např. pro Command assertText je text, který v elementu má být).

Když máme hotové kontroly které jsme schopni provést v samotném Selenium IDE, klikneme na File > Export Test Case As > Java / JUnit 4 / WebDriver. Bohužel Selenium IDE v aktuální verzi neumí kombinaci Java / TestNG / WebDriver, bude tedy potřeba test převést, s pluginem pro TestNG v Eclipse je to však otázka pár kliknutí.

export do Javy

Dostaneme soubor s kostrou testu, může vypadat například takto:

package com.example.tests;

import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;

public class Test {
	private WebDriver driver;
	private String baseUrl;
	private boolean acceptNextAlert = true;
	private StringBuffer verificationErrors = new StringBuffer();

	@Before
	public void setUp() throws Exception {
		driver = new FirefoxDriver();
		baseUrl = "http://localhost:8080/";
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	}

	@Test
	public void test() throws Exception {
		driver.get(baseUrl + "/idm/admin/authentication/login.seam");
		driver.findElement(By.id("j_id12:username")).clear();
		driver.findElement(By.id("j_id12:username")).sendKeys("admin");
		driver.findElement(By.id("j_id12:password")).clear();
		driver.findElement(By.id("j_id12:password")).sendKeys("admin");
		driver.findElement(By.id("j_id12:submit")).click();
		driver.findElement(By.id("reportsLink:j_id60")).click();
		driver.findElement(By.name("j_id100:submenu_table:j_id109")).clear();
		driver.findElement(By.name("j_id100:submenu_table:j_id109")).sendKeys("admin");
		driver.findElement(By.name("j_id100:submenu_table:j_id137")).click();
		driver.findElement(By.id("j_id32")).click();
	}

	@After
	public void tearDown() throws Exception {
		driver.quit();
		String verificationErrorString = verificationErrors.toString();
		if (!"".equals(verificationErrorString)) {
			fail(verificationErrorString);
		}
	}

	private boolean isElementPresent(By by) {
		try {
			driver.findElement(by);
			return true;
		} catch (NoSuchElementException e) {
			return false;
		}
	}

	private boolean isAlertPresent() {
		try {
			driver.switchTo().alert();
			return true;
		} catch (NoAlertPresentException e) {
			return false;
		}
	}

	private String closeAlertAndGetItsText() {
		try {
			Alert alert = driver.switchTo().alert();
			String alertText = alert.getText();
			if (acceptNextAlert) {
			alert.accept();
		} else {
			alert.dismiss();
		}
			return alertText;
		} finally {
			acceptNextAlert = true;
		}
	}
}

Umístíme jej tedy do vhodného package mezi testy, já jsem zvolil eu.bcvsolutions.idm.test.ui.admin.selenium. V Eclipse na něj klikneme pravým tlačítkem a zvolíme TestNG > Convert to TestNG. Pravděpodobně nebudete chtít vygenerovat testng.xml, ale budete test chtít přidat do hlavního testng.xml, aby se spouštěl s ostatními testy.

V BCV solutions testujeme automaticky pomocí Jenkins, proto je připravena třída eu.bcvsolutions.idm.test.SeleniumTest, ze které testy dědíme. Poskytuje předpřipravené metody setUp a tearDown pro testování více prohlížeči. Stačí jednoduše přidat na začátek import eu.bcvsolutions.idm.test.SeleniumTest a k deklaraci třídy extends SeleniumTest a smazat vygenerované metody setUp a tearDown. V testng.xml přidáme naši třídu ke všem prohlížečům (ChromeTest, FirefoxTest, případně do budoucna další) a nyní se bude test spouštět postupně na všech. Také nám tato třída poskytuje metody logIn a logOut aby se nám stále neopakoval stejný kód.

Nyní je vhodný čas zkusit, jestli test správně proběhne. Pokud ano, můžete se pustit do pokročilejších kontrol, nyní už v Javě, a tedy mnohem pohodlněji než v Selenium IDE. Můžete si například najít tabulku s výsledky a kontrolovat, zda obsahuje po přefiltrování správná data.

K tomu máme k dispozici třídu eu.bcvsolutions.idm.test.SeleniumTestUtils, ve které je prozatím metoda pro kontrolu, zda sloupec tabulky (ne)obsahuje hodnotu X, do budoucna se jistě rozšíří, abychom nemuseli časté typy kontrol psát stále znovu.

Na co si dát pozor do budoucna

V budoucnu se CzechIdM bude jistě rozrůstat o další funkce, s tím souvisí nejen drobné změny vzhledu (další položky v menu, …) ale i testovacích dat. Může se tedy stát, že nám mezi existující položky přibudou další, musíme tedy s touto variantou počítat a nedělat testy až přespříliš striktní, typu „v X-tém řádku, Y-tém sloupci bude hodnota Z“ ale například „někde v Y-tém sloupci bude hodnota Z“, což je problematické přímo v Selenium IDE a lépe se řeší už v Javě. Sice to stále neřeší všechny situace (např. že data padnou na další stránku), ale alespoň většinu z nich.

Pozor na ID elementů

V aktuálním release má spousta HTML elementů ID vygenerované automaticky díky JSF. Zde narážíme na problém, protože pokud v rozhraní přibude element, JSF posune číslování, tedy veškeré kontroly spoléhající na ID elementu selžou. O tomto problému víme a budeme ho v brzké době řešit dogenerováním vlastních ID. Prozatím je potřeba počítat s úpravou testů pro nové verze a nebo se snažit psát kontroly, které na ID nezáleží.

Závěr

Selenium testy jsou jistě zajímavým tématem k hlubšímu studiu a někdy se k nim určite vrátím. V případě že máte nějaké otázky, nebo postřehy k tomuto článku, mužete psát na jiri.novak@bcvsolutions.eu.

Framework pro automatické testování jBPM Workflow zobrazujících formuláře

Předmětem článku je automatizace integračních testů jBPM Workflows pro CzechIdM. Poměrně často potřebuje workflow v nějaké své fázi převzít uživatelská data z formuláře. To je problém v případě automatického testu, kde uživatele nemáme. Pokud se nechceme pustit do zdlouhavého shánění nebohých dobrovolníků, či se uchýlit k použití Selenia, musíme si vytvořit vlastní způsob simulace formulářového vstupu. Následující text se zabývá tímto problémem včetně úpravy řešení do jednoduchého frameworku. Pokračování textu

Automatické testování Java aplikace pomocí nástrojů TestNG a Apache ANT (Unit testing)

Tento článek popisuje způsob automatického testování JAVA aplikací pomocí nástrojů TestNG a Apache ANT. Testovaná aplikace je napsána na platformě J2EE pomocí frameworku JBoss Seam.

Před časem jsem dostal za úkol vyřešit automatické spouštění unit testů pro aplikaci, kterou vyvíjíme. Jako vývojové prostředí používáme Eclipse. Samotné unit testy píšeme pomocí nástroje TestNG. Cílem tedy bylo vytvořit nástroj, který si stáhne aktuální verzi aplikace z SVN repository. Aplikaci zkompije a spustí testy. Tedy se jedná o tzv. unit testy.

Úkol jsem si nejprve rozdělil na několik dílčích částí:

  • stažení dat z SVN serveru
  • build aplikace
  • spuštění unit testů

Stažení dat z SVN, jak se později ukázalo, je velice snadné. Použil jsem Apache ANT a knihovny pro práci s SVN:

<path id="svnant.class.path">
	<pathelement location="lib\svnant.jar" />
	<pathelement location="lib\svnClientAdapter.jar" />
	<pathelement location="lib\svnjavahl.jar" />
	<pathelement location="lib\svnkit.jar" />
</path>

<typedef resource="org/tigris/subversion/svnant/svnantlib.xml" classpathref="svnant.class.path" />

<target name="svn">
	<svn username="username" password="password"> 
		<checkout url="url" revision="HEAD" destPath="path" />
		<!--<update revision="HEAD" dir="${projectPath}" />-->
	</svn>
</target>

Checkout se použije při prvním stažení, poté se neprovádí checkout, ale update.

Problém nastal u buildu aplikace. Jak již jsem zmiňoval, jako vývojové prostředí používáme Eclipse a plugin pro práci s frameworkem JBoss Seam. Tento plugin nám zajišťuje build aplikace a deploy na aplikační server. Plugin pro práci s TestNG nám zajišťuje spouštění testů – tzn. deploy aplikace na tzv. embedded JBoss a provedení testů.

Zdálo se zbytečné psát pomocí buildovacího nástroje ANT či Maven script pro build aplikace. Proto jsem se rozhodl vyhledat nástroj (plugin), který by byl schopný vzít data z Eclipse workspace a provést build. Našel jsem nástroj ant4eclipse, o kterém jsem se dočetl, že podobnou věc umí.

Po mnoha neúspěšných pokusech jsem zaslal dotaz do fóra, ve kterém jsem se ptal, jakým způsobem se provádí build Java aplikace (Seam + J2EE + JSF). Překvapivě rychle jsem dostal odpověď, že nástroj takovouto aplikaci buildit neumí. (Zajímá-li vás však build „obyčejné“ Java aplikace, určitě vám doporučuji se na nástroj podívat.)

Protože jsem žádnou další alternativu neobjevil, nezbylo mi nic jiného, než napsat vlastní ANT build script. Přesto, že jsem s ANT-em nikdy nepracoval, nezdál se být úkol až tak těžký. Podíval jsem se, jak vypadá build, který provádí Eclipse – tedy ten, který se nachází na aplikačním serveru (v našem případě to byl JBoss AS). Tohoto jsem se držel – jen tak mimochodem, již po několika desítkách minut práce s ANT-em zjistíte, proč se nástroj jmenuje ANT – je to opravdu mravenčí práce. :-)

Když už se konečně zdálo, že mám hotovo, hodně jsem se zmýlil! Sice jsem vytvořil strukturu aplikace, kterou bylo možné nahrát na aplikační server, problém však byl se spuštěním testů.

Nástroj TestNG spouští totiž testy ne přímo na aplikačním serveru, ale na tzv. embedded JBoss. Tady jsem opravdu narazil, protože jsem nebyl schopen nakonfigurovat buildovací script tak, aby úspěšně spustil embedded JBoss a provedl testy.

Prošel jsem si ukázkové aplikace k frameworku Seam a zjistil jsem, že je zde možné testy spouštět. Protože spuštění mi zafungovalo a testy se úspěšně provedly, řekl jsem si, že projdu buildovací scripty ukázkové aplikace a spustím testy obdobným způsobem. (Tady jsem si potvrdil svůj úsudek o tom, že psaní a editace build scriptů je opravdu mravenčí práce) Skutečně jsem spouštění testů nalezl, zkopírovaní a použití v naší aplikaci však bylo velice komplikované. Sada buildovacích scriptů examplů se všemožně includuje a nalézt skutečné hodnoty zástupných proměnných bylo poměrně dost náročné.

Jelikož i zde jsem narazil, napadla mě jiná možnost – použít buildovací script pro ukázkovou aplikaci Seamu na naši aplikaci. Jelikož tato ukázková aplikace má jinou strukturu, bylo nutné upravit výstup z mého ANT-ovského buildu do podoby, která bude totožná s ukázkovým příkladem Seamu.

Toto je podoba upraveného projektu do podoby, ve které jsou všechny Seam examply:

  • jboss-seam
    • bootstrap
    • build
    • classes
    • examples
      • naše aplikace
        • resources
        • src
        • view
        • build.xml // zkopírovaný ze seam examplu. Stačí provést editaci názvu aplikace a resourcu – tzn. souboru, kde se definuje URL databáze.
    • lib
    • test-output
    • ui
    • build.xml // testo soubor je přesně ten, který je v examplech, build.xml z naší aplikace pomocí něho spouští TestNG testy

Pro úspěšné spuštění testů stačí spustit build.xml (target = test) z naší aplikace:

Jen pro doplnění – vytvoření struktury, která je shodná s tou, kterou generuje Eclipse nebylo zbytečné – je možné ji automaticky deployovat do testovacího prostředí. Samozřejmě automatické spouštění scriptu je třeba nastavit na testovacím serveru.

Na závěr tedy shrnutí postupu:

  • stažení aktuální verze aplikace z SVN repository
  • odstranění předchozího buildu
  • build EJB vrstvy
  • build webové vrstvy
  • build unit testů
  • zkopírování buildu do souboru /seam/examples/nase_aplikace
  • spuštění příkazu ant -f seam/examples/nase_alikace/build.xml test
  • Přestože řešení buildu není úplně „čisté“, je použitelné. Máme tak nástroj, který automaticky testuje aktuální verzi naší aplikace. Jako odměnu pro ty, kteří dočetli až sem, si dovolím přidat trochu teorie a pojmů o testování SW, kterou jsem pochytil ve školních lavicích :-)

    Testování jednotek
  • Zaměřujeme se na malé kusy zdrojového kódu – na jednotlivé funkce.
  • Testujeme např. okrajové podmínky, cesty pro zpracování chyb,…
  • Integrační testování
  • Integrace zdola nahoru
    • spojíme nejnižší moduly
    • napíšeme řídící modul, který bude koordinovat práci mezi spojenými moduly
    • otestujeme skupinu
    • odebereme řídící modul a pospojujeme se skupinami ve vyšší struktuře
  • Integrace shora dolů
    • Vezmeme hlavní modul a maketami nahradíme nižší moduly
    • Postupně měníme makety za reálné moduly s tím, že po každém přidání modulu systém otestujeme.
    • Cílem je ověřit, že přidáním modulu nedošlo k zanesení chyby do aplikace.
    • Nevýhodou je nutnost tvorby maket modulů.
  • Validační testování
  • Slouží k ověření, že aplikace splňuje požadavky zákazníka.
  • Provádí se metodami black-box testování.
  • Do této kategorie spadají např. akceptační testy.
  • Systémové testování
  • Skupina různých testů, která prověřuje celou systémovou architekturu (HW, SW, administrátory).
  • Bezpečnostní testování (odolnost proti útokům hackerů).
  • Testování obnovy (ověření, že poruchy byly odstraněny ve smluveném termínu).
  • Zátěžové testování (sledování chování programu při velikém zatížení – tzn. simulace velkého počtu připojených uživatelů).
  • Black-box testování
  • Jedná se o testování správného provádění navržených funkcí aplikace. Ne vždy u tohoto způsobu známe všechny potřebné informace o implementaci.
  • Tento způsob testování nemusí nutně postihnout celý kód aplikace.
  • White-box testování
  • Při tomto způsobu testování známe informace o vnitřní struktuře aplikace, kterou testujeme.
  • Testujeme
    • všechny samostatné cesty uvnitř modulu
    • všechny podmínky se projdou větví s hodnotami ano i ne
    • všechny cykly
    • všechny vnitřní datové struktury
  • Na úplný závěr si dovolím jednu větu, která charakterizuje testování (rád bych citoval, ale autora věty si nepamatuji):

    Úspěšný test je takový, který objevil doposud neobjevené chyby.