fredag 27 november 2009

Jag vill ha en databas i rött och grönt!

Alltså det här med automatiska tester är ju "old news" vid det här laget. Ja, att automatiska tester finns är ingen nyhet, men användningen av det är fortfarande nytt för många av oss, inte minst mig själv.
Med en kodbas på 100.000-tals rader kod är ett par hundra tester inget vidare facit. Men, nu var det inte det jag funderade på...

Vad jag länge funderat över är hur man testar databasen och DB2 i synnerhet. Det finns ju fina grejer som "Linq to SQL" eller "Visual Studio for Database Developers". Men - det gäller ju allt som oftas SQL Server. Jag har absolut inget emot MSSQL, tvärtom! Men, nu sitter jag inte med Microsoft utan med IBM DB2. Det finns mycket att säga om den, men i vår utvecklingsgrupp har vi efter en del besvärligheter äntligen hittat bra vägar att utveckla mot DB2.

Men att jobba med databaser innebär ju att man, hur man än vänder och vrider på accessen mot den, delar sin applikation i minst två delar. En del kör Stored Procedures med affärslogik (not my flavor...), en del SP's som ersättning mot SQL i koden (smakar bättre) och en del släpper loss med SQL kod blandat med den vanliga källkoden (smakar bäver). O/R mappers eller inte, databasen är en del av applikationen. Att designa och bygga den är en vital del av att bygga applikationen.

Men säg då att man valt SQL i koden, då är väl bara DB:n ett dumt lager? Nä. Det finns fortfarande triggers, referensintegritet, vyer... Så länge man lagt kod i databasen på ett eller anat sätt är det också en del av applikationen och måste på så vis också testas.

Okej. Du har inga triggers och ingen RI (skojar du eller?). Vet du vad, du har fortfarande ett testbehov! Vad händer om du förändrar schemat. Vad händer om du lägger till en kolumn eller byter en datatyp? Vad händer om någon annan gör det utan att du vet om det? Hur testar man att applikationen klarar det? Ofta tror man att "ja, men en sån ändring påverkar ju inte någon annan applikation". Men hur vore det att verkligen veta?

Nog om behovet. Det finns.

Min önskan är att jag skulle kunna lägga mina tester av databasen tillsammans med testerna av den övriga koden. Att få samma inbyggda Visual Studio stöd för mina tester. Att enkelt kunna testa fram om min nya release gör det den ska i databasen och hur bakåtkompatibel  den är.

Att testa att rätt saker händer i databasen
Det här ju egentligen rätt elementärt. Du ser till att databasen ser ut på ett visst sätt, att vissa data finns och att andra inte gör det. Du kör din kod. Du kontrollerar att rätt saker hänt.
Men hur gör man det på ett sätt som låter oss inkorporera det i Visual Studio tester?

Låt oss skapa en struktur av hjälpklasser som representerar databasen vid ett givet tillfälle, ett snapshot. Det rymmer sig extremt mycket information i databasens metadata, så det här kan autogenereras. Egentligen liknar min vision egentligen typade dataset, men med mindre buggar och kanske en aaaning snabbare.

Okej, jag ger mig på ett försök att förklara tanken med lite pseudokod.

Vi tänker oss en tabell med kunder som vi ska testa mot. Vi börjar med att se till att vår testkund inte finns redan.

TableCustomer.DeleteIfExists(12345); 

Varje tabell har ett antal hjälpmetoder, för att skapa, ta bort eller uppdatera rader. Vi känner till metadatan och vilka fält som är nycklar samt vilka som är NOT NULL. Det gör att vi kan skapa alla möjliga operationer mot databasen automatiskt. Särskilt mycket nytta får vi av de som arbetar mot primärnyckeln (som givetvis INTE behöver vara ett RowId, utan kan vara sammansatt)

När vi väl tagit bort kunden, kan vi köra vår riktiga kod. I detta fall ett anrop på en SP som skapar en kund.

// Detta är produktionskoden, ett anrop på en stored procedure
CustomerProxy.SaveCustomer(12345, "Test Customer", "West street 25", "Waynesburg, PA");

TableCustomer.Row row = TableCustomer.GetByPrimary(12345);
Assert.IsNotNull(row);
Assert.AreEqual(12345, row.CustomerId);
Assert.AreEqual("West street 25", row.StreetAdress);
Assert.AreEqual("Waynesburg, PA", row.CityAdress);


För de av er som ifrågasätter min simpla och uppenbart sunkiga datamodell - grattis! Ni lider av samma skada som jag. Men det är inte det viktiga. På ett enkelt sätt har vi testat att databasen ser ut som vi tänkte oss.Dessutom har vi gjort det med unit tests och testmöjligheterna är autogenererade.

Men vi har ytterligare en vinst: Vi märker när schemat ändras. Om någon skapar nya fält som krävs av kundtabellen kommer vår snapshot inte att fungera. Vår SP kommer inte heller fungera.

Om vi autoskapar vår snapshot varje natt i samband med det nattliga bygget kan vi få med alla de ändringar som skett i databasen. På det sättet kan vårt snapshot hänga med i förändringarna. Då blir det rätt uppenbart om någon ändrat någonting som påverkar våra tester. Efter vårt bygge kör vi ju givetvis vårt stora testpaket och hittar då en eller flera röda "pluppar" i testprotokollet.

Inte nog med det! Om vi inkluderar vårt snapshot med vår release som just nu ligger i produktion så vet vi vad applikationen förväntar sig av databasen. Det gör ju att testerna av releasen direkt smäller om någon släppt en "helt ofarlig ändring". Detta eftersom vi givetvis inte genererar om releasens snapshot utan kör på det den förutsatte vid releasetillfället.

Eller, ännu bättre! Om vi istället kör två uppsättningar tester av vår releasekod, en med den gamla snapshoten och en med en helt ny autogenererad snapshot. Då ser vi om vår kod klarar av den nya strukturen. Två sätt att testa samma sak, men ur olika vinkel och på det viset bättre!

Jag vet inte om ni har hängt med på hälften av det jag yrat om eller om det ens verkar vettigt. Jag brinner verkligen för det här ämnet och om allt vill sig väl hoppas jag presentera lite exempelkod vad det lider.

Kanske finns det till och med visst stöd i befintliga lösningar därute:
http://db2unit.sourceforge.net/
http://www.theserverside.net/discussions/thread.tss?thread_id=23702
http://www.anydbtest.com/

Vad som än finns i dessa lösningar, är själva idén något jag tror starkt på!

Phew! Dags att släppa vilda databastester för ett tag och ta helg!

Over and out!

Dagend kodarmusik: C-Quence - Endorphine (Original mix edit)

Inga kommentarer:

Skicka en kommentar