středa 21. března 2012

Automatické testování proti databázi

Proti databázi budete zřejmě spouštět testy pokrývající datovou vrstvu. U vyšších vrstev aplikace, použijete testovací databázi v situacích, kdy není vhodné datovou vrstvu mockovat. Testovací databáze se bude hodit v případě zátěžových a výkonnostních testů.

Dostupnost testovací databáze

Testy potřebujete spouštět na pracovních stanicích vývojářů, na buildovacím serveru nebo na jiném počítači, který nemusí být nutně připojen k počítačové síti. Je obvyklé, že databáze se zpřístupní v okamžiku spouštění testů a po jejich provedení se zahodí.

Není také vhodné, aby více běhových testovacích prostředí přistupovalo na stejnou instanci databáze. Mohly by se vzájemně ovlivňovat v operacích, které nejdou schovat do transakce (např. DDL příkazy).

Z uvedených důvodů se používají lokální databáze. V odůvodněných případech můžete použít i serverovou instanci databáze, ale toto řešení přináší jistá omezení plynoucí ze společného přístupu více testovacích klientů.

Rychlost vytvoření lokální databáze

Jeden z důležitých požadavků kladených na testy je jejich rychlost provádění. A databázové testy patří mezi ty nejpomalejší. Pokud používáte lokální databázi, musíte počítat s časovými režijemi na vytvoření instance databáze.

Nejrychleji startují paměťové (in-memory) databáze (např. SQLite) a databáze pracující nad datovými soubory. Pokud je vaše datová vrstva nezávislá na konkrétním typu databáze, můžete pro účely testů použít některou z rychlých variant, která neodpovídá produkční databázi. Např. u zákazníků běží vaše aplikace na MS SQL Serveru a na Oracle, ale testujete proti SQLite.

Jak to funguje u nás

V naší firmě jsme zvolili testovací databázi stejnou jako produkční a to MS SQL Server. Každý počítač, na kterém chceme spouštět testy, má instalován plnotučný MS SQL Server nebo alespoň MS SQL Server Express (na vývojářských stanicích). Při této variantě je nutné databázi obnovit (příkaz restore) z lokálního .bak souboru. Naše databáze má více jak 1000 tabulek a její obnovení trvá do 10 sekund. Optimalizací je to, že databázi obnovujeme pouze jednou, na začátku spouštění sady testů.

Soubor s databází je vytvářen ze serverové databázové instance, ke které je omezený přístup. Jsou na ní spouštěny pouze schválené změnové skripty a přímo na ní se netestuje. Soubor je uložen v systému pro správu zdrojových kódů a je synchronizován spolu se zdrojovými produkčními kódy a testy na počítač, kde se testy spouští.

Vývoj a spouštění testů probíhá nad více vývojovými větvemi. Pro každou větev je k dispozici kompatibilní databázový soubor s příslušnou strukturou.

Testovací data

Aby bylo možné validovat výsledek spuštění každého testu, musí být splněny vstupní podmínky. V případě testů proti databázi musí být k dispozici taková testovací data, která předpokládá test. Ideální situací je prázdná databáze před testem. Všechna data jsou pak v inicializaci testu do databáze vložena skriptem. Složitost databázových skriptů se liší podle testovaného problému a složitosti vazeb do podřízených tabulek.

Vyhněte se přípravě testovacích dat pomocí programových tříd. Může se stát, že test selže ve fázi právě této přípravy testovacích dat. Tím se celý test znehodnotí a chybně indikuje problém, který je zřejmě jinde než v testované části kódu. Navíc zbytečně zvyšujete složitost kódu testů.

Někdy může být výhodné mít v databázi část dat předvyplněných. Jedná se o data, která mají referenční charakter (jsou stejná na všech instalacích) nebo o data, která využívá většina testů - testovací aplikační uživatelé, testovací osoby, apod. Taková data musí být neměnná a testy s nimi musí počítat.

SQL skripty generující testovací data ukládejte do repository. Jeden skript může být použit pro celou sadu testů. Dokonce si dovedu představit, že skript, který generuje např. testovací objednávky, bude použit v testech datové vrstvy objednávek i funkcionality WCF služby pro práci s objednávkami.

Užitečné tipy

Uzavřete provádění celého testu do transakce, která vždy skončí příkazem rollback. Pro promítnutí změn do databáze použijte příslušnou funkci vašeho perzistentního frameworku. Např. pro (N)Hibernate je to funkce Flush() databázové relace.

Databázový uživatel, pod kterým spouštíte testy, by měl mít stejná oprávnění jako v produkčním prostředí. Vyhněte se uživatelům s DBA právy a uživateli, který je vlastníkem databázových struktur. Pod takovými uživateli může test projít, ale v produkci dojde k chybě.

Pokud se chcete vyhnout časově náročné obnově databáze před každým testem, můžete si pomoci "úklidem" databáze. Před nebo po každém testu spustíte skript, který smaže všechna data. V případě, že se vám daří provádět testy v transakci s rollbackem, nebude zřejmě úklid nutný.

Závěrem

Vyberte si vhodnou strategii, která bude vyhovovat vašim potřebám. Efektivní vytváření a spouštění testů zvýší vaši produktivitu práce a vnese potřebnou jistotu do udržovatelnosti aplikace.