Testujeme WS klienty

Chystám se přihřát si vlastní polívčičku a budu psát o tom, na čem právě ve svém volném čase dělám. Jde o knihovnu, která mi pomáhá s testováním Spring WS klientských aplikací. Jako obvykle jsem si chtěl ušetřit sám sobě práci. Jsem totiž docela nakažen testováním, takže se snažím psát unit testy skoro na všechno co dělám.

Některé části aplikace se ale testují dost špatně. Většinou jde o „okraje“ aplikace jako například JSP, komunikaci s databází, volání webových služeb nebo proprietárního kódu. Jinými slovy, pokud je testovaný kód používaný pouze mým kódem, testuje se docela dobře. Pokud je ale na rozhraní mezi mnou a uživatelem, databází nebo něčím jiným, testování se komplikuje.

Proto je důležité psát takové části co nejtenčí. Co to znamená? Vaše JSP stránky by měly být co nejjednodušší, DAO vrstva by neměla obsahovat žádnou logiku a knihovny které používáte by měly být co nejméně invazivní.

Pokud ale tyto věci na periferii chci otestovat, musím se často uchýlit k funkčním testům. K testům, které jsou sice automatizované, ale které vyžadují běžící aplikační server, Spring kontext nebo třeba databázi v paměti jako HSQL. Takové testy jsou obvykle komplikovanější a také jejich spouštění trvá výrazně děle.

Podobný problém mívám i s testy volání webové služby. Samosebou mám toto volání zapouzdřeno ve speciální vrstvě, ale i tu bych rád otestoval. Kód často vypadá podobně jako tento.

public List<Flight> getFlights(String origin, String destination) {
	//prepare request
	GetFlightsRequest request = new GetFlightsRequest();
	request.setFrom(origin);
	request.setTo(destination);
	request.setServiceClass(ServiceClass.ECONOMY);
	request.setDepartureDate(Calendar.getInstance());
	//call the service
	GetFlightsResponse response = (GetFlightsResponse)webServiceTemplate.marshalSendAndReceive(request);
	//convert response
	return response.getFlight();
}

Na začátku musím vyrobit dotaz. Obvykle musím naplnit nějaký objekt vygenerovaný XML mapovacím nástrojem. Pak zavolám službu a její odpověď musím zase převést na něco čemu rozumí moje aplikace.

Jak něco takového otestovat? Samozřejmě to jde, jenom mě to vůbec nebaví. Nejdřív potřebuji otestovat, že jsem správně vytvořil dotaz. Pokud to testuji klasicky, tak ten test vypadá podezřele stejně jako kód samotný. Hrozně mě nebaví testovat, jestli když nastavím datum odletu, tak je opravdu dobře nastaveno. Navíc je to hrozně odtrženo od požadavků. Nikdo po mě přeci nechce, abych plnil nějaký hloupý vygenerovaný objekt. Chtějí po mě, abych vygeneroval XML. Věřím sice, že XML mapovací knihova funguje správně, ale pořád mám pocit, že by bylo pěkné to otestovat nějak lépe.

Pak by bylo dobré otestovat, jestli opravdu volám tu webovou službu. Další trapný a nudný test. Nastavím mock a ověřím, jestli se opravdu zavolá. Nůůůda.

No a pak mě čeká otestovaní, jestli se dobře konvertují data z odpovědi do objektu, který má často podobnou strukturu. Další nuda.

Dá se to dělat lépe? Samozřejmě. Za pomocí našeho skvělého patentovaného přípravku, který vyčistí všechny vaše testovací skvrny bez narušení podstaty látky. Můžeme si totiž připravit požadovaný dotaz i odpověď jako XML, použít naši speciální knihovnu a napsat test například takto

@Test
public void testGetFligts()
{
	
	//create control
	WsMockControl mockControl = new WsMockControl();
	//teach mock what to do and create it
	WebServiceMessageSender mockMessageSender = mockControl.expectRequest("PRG-DUB-request.xml").returnResponse("PRG-DUB-response.xml").createMock();
	webServiceTemplate.setMessageSender(mockMessageSender);
	
	//do the test
	List<Flight> flights = client.getFlights("PRG","DUB");
	assertNotNull(flights);
	assertEquals(1, flights.size());
	assertEquals("PRG",flights.get(0).getFrom().getCode());
	assertEquals("DUB",flights.get(0).getTo().getCode());
	
	//verify that everything was called at least once
	mockControl.verify();
}

Krásné, jednoduché a elegantní. Popis XML dat je realizován v k tomu nejvhodnějším jazyce - v XML. Test mi i automaticky ohlídá, že jsem opravdu službu zavolal. A to nezmiňuji spoustu dalších vymožeností, které zde pro jistotu nezmiňuji, abyste ohromením neomdleli.

Pokud jste tedy zůstali při vědomí vězte, že to všechno je k mání zdarma, na adrese http://javacrumbs.net/spring-ws-test/. Jenom račte prominouti, že dokumentaci ještě nestačila býti plně dohotovena. Naše dokumentační oddělení na ní pilně pracuje tudíž se lze domnívati, že bude dohotovena v nedaleké budoucnosti. Prozatím račte vzíti v potaz příklad použití, který Vám návod jistojistě poskytne.

2 Responses to “Testujeme WS klienty”

  1. Dagi Says:

    No opravdova nuda je vytvaret tyXMLka ;-). Neuvazujes o tom, ze pridas nejakou tenkou vrstvu, ktera ti bude umoznovat nacmuchat to XML co bezi po dratech to pouzit po zkontrolovani jako ocekavany vstup a vystup?

  2. Lukáš Křečan Says:

    Neuvažuju. Já mám rád TDD, takže chci mít obě XMLka připravená ještě před tím, než mám vůbec nějaký kód! Kdybych je načmuchal, tak by to znamenalo, že už mám něco, co je generuje. Takže by to bylo asi ohromně užitečné pro regresní testy, ale už moc ne pro unit testy.