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.

5 komentářů:

  1. Přijde mi, že spolu úzce souvisí databázové migrace a příprava databáze pro běh aplikace (jak na produkci, tak v testech).

    Jak to máte u vás v téhle konfiguraci s databázovýma migracema?

    My to máme udělaný tak, že máme sadu databázových migrací (up a down z/do verze) a aplikace ví, jakou verzi databáze potřebuje. Potřebné migrace se pouští před každým testem a při nasazení nové verze aplikace. Works like a charm.

    OdpovědětVymazat
    Odpovědi
    1. Pěkné řešení. Takhle zcela automatizované to zatím nemáme :( Změnové databázové skripty evidujeme ve vývojovém repozitáři a spouštíme manuálně (v testech i produkci). Vyvíjíme "nekrabicové" podnikové IS, které jsou poměrně rozsáhlé a u mnoha zákazníků přistupují do databáze další aplikace. Každé nasazení nové verze u zákazníka musí projít zkušebním procesem. Navíc podporujeme Oracle i MS SQL a tím se situace zase trochu komplikuje.

      Ale na procesu automatizace migrace databáze se pracuje ...

      Vymazat
  2. No tak na zelanie, ako riesime migracie u nas:
    - na starsom projekte je to normalne pomocou instalatora prebehne update script ak db existuje (verzia db normalne v tabulke settings), pripadne full script pre kazdu verziu ak je nova instalacia
    - na mensich novsich projektoch update cez nhibernate updateschema (dosial ziaden problem) ale tam pouzivame nhibernate aj na generovanie schemy cez createschema a vlastne pri nich takmer neprichadzam do styku s sql (okrem specialnych stat queries)

    OdpovědětVymazat
    Odpovědi
    1. Super, vypadá to efektivně. Tu automatizaci nasazení vám závidím ;)
      updateschema tahá DDL definice odkud? Z mapování tříd? Máte ještě nějaké další skripty? A typ produkční databáze?

      Vymazat
    2. Jo vyber NHibernate ako orm ma nieco do seba ale nie je vsetko zlato, co sa bližčí. Moze nastat scenar, ked takyto automaticky update nebude fungovat, potom je treba siahnut po manualnom rieseni, sice aj to nhibernate podporuje ale uz je to praca navyse, s ktorou treba teoreticky ratat.

      Vymazat