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 info@bcvsolutions.eu.