home techniek

Test Driven Development

Door René van Osnabrugge - .NET ontwikkelaar bij Delta-N

Vaak is het een ondergeschoven kindje. De overgebleven uurtjes worden erop geschreven, en als de deadline in zicht komt is het het eerste waarop wordt bespaard. Testen is het zwarte schaap van software ontwikkeling.

De laatste jaren is er echter een verschuiving merkbaar. In plaats van kant en klare software te testen, wordt de software getest tijdens het schrijven ervan. Dit concept is gevat in de term Test Driven Development. De term spreekt voor zich. Software wordt ontwikkeld door het schrijven van tests. Dit leidt tot goed geteste, minimale, zelf documenterende en vooral onderhoudbare code.

Een zeer belangrijk onderdeel in Test Driven Development is zonder meer het schrijven van Unit Tests.

In de wereld van Test Driven Development (TDD) wordt begonnen met het maken van tests. Een goede tool om automatisch mee te kunnen testen is NUnit. Op de site www.testdriven.net is een add-in voor Visual Studio.NET te downloaden, die Visual Studio voorziet van een aantal extra tools om goed te kunnen werken met Unit Tests.

Unit Tests stellen je in staat om iedere afzonderlijke functie te testen, op verschillende manieren. Al deze tests worden geautomatiseerd uitgevoerd en blijven altijd bestaan. Dit betekent dat bij code aanpassingen alle tests nog moeten werken. Als dit niet het geval is zijn er 2 mogelijkheden.

  • De code is veranderd en werkt niet meer. Pas de code aan zodat de tests weer allemaal slagen
  • De functionaliteit is veranderd. Pas de test aan.

Doordat alle tests iedere keer worden uitgevoerd, worden functionele wijzigingen (soms per ongeluk) direct opgemerkt.

In onderstaand voorbeeld wordt een volledig programma inclusief tests behandeld. Dit voorbeeld gaat ervan uit, dat TestDriven.Net is geinstalleerd.

Voorbeeld:

Laten we eens een simpel programma bedenken waarbij Unit Tests tot hun recht komen. We gaan een rekenmachine maken. Deze rekenmachine kan 4 dingen: optellen, aftrekken, vermenigvuldigen en delen.

We maken in Visual Studio 2 “Class Library” projecten aan. Een “Class Libary Project” genaamd ”Rekenmachine.Services” en een project “Rekenmachine.Tests”. Hiermee voorkomen we dat we code en tests door elkaar heen gaan schrijven. Tests mogen namelijk nooit en te nimmer deel uitmaken van productiecode. Door de tests in een afzonderlijk project onder te brengen, wordt dit voorkomen.

fig 1

Figuur 1

In “Rekenmachine.Tests” leggen we een “reference” naar het ”Rekenmachine.Services” project. Hiermee bewerkstelligen we dat het Test project het services project kan testen.

Verder leggen we references naar de dll’s van “Nunit.Framework” en “Nunit.Core”. Deze zijn te vinden in de directory waar TestDriven.NET is geinstalleerd (c:\program files\testdriven.net\Nunit). Beter is nog om een directory “Library” te maken op dezelfde locatie als de sourcecode, en hier de dll’s in te kopieren. Zo blijft alles netjes bij elkaar, en versie conflicten worden uitgesloten.

Maak in het Test project een class aan en noem deze “RekenServiceTestFixture”. Dit wordt de class die de RekenService gaat testen.

Zet boven de class het attribuut [TestFixture]. Dit zorgt ervoor dat Nunit deze class meeneemt in de test. Zet boven iedere test functie het attribuut [Test]. Dit zorgt ervoor dat de functie meegenomen door Nunit.

Bekijk onderstaande code en neem dit over. Deze code (testOptellen1), creeert een nieuwe RekenService. Op deze RekenService wordt de functie “Optellen” aangeroepen, en deze ontvangt 2 parameters. Door Assert.AreEqual(20,x), vertellen wij Nunit dat het verwachte resultaat 20 is, en dat de functie Optellen dit moet opleveren als wij (10,10) er heen sturen.

code 1

CodeSnippet 1

Als de code wordt gecompileerd, zal deze een fout geven, namelijk dat de Class RekenService niet bestaat. Dit is juist omdat we deze nog niet hebben gemaakt. Test Driven Development schrijft immers voor dat er eerst een test moet zijn. De test wijst dus uit dat er een class “RekenService” moet komen die een functie “Optellen” heeft, 2 parameters ontvangt en een “int” terug geeft.

Maak in het ”Rekenmachine.Services” project een class “RekenService” met daarin een method Optellen. Laat deze method 20 teruggeven.

code 2

CodeSnippet 2

Met de code in CodeSnippet 2 zorgen we dat de test die we hebben verzonnen zal slagen. Check dit door op het project Rekenmachine.Tests op de rechter muis toets te klikken en Run Tests te kiezen. Deze mogelijkheid wordt geboden door de installatie van TestDriven.NET. In het Output Window zal de tekst “1 succeeded” komen te staan.

fig 2

We gaan echter verder testen. We maken een functie testOptellen2, die een 10 en een 20 naar de RekenService stuurt.

code 3

CodeSnippet 3

Als we nu de test runnen, zien we dat er 1 succeed en 1 failed. De functie verwachtte 30 als uitkomst maar er kwam 20 uit.

code 4

Figuur 3

We gaan dus de functie Optellen aanpassen.

code 5

CodeSnippet 4

Als we de test opnieuw runnen, zien we dat de eerste test nog steeds slaagt. We weten dus dat we geen bestaande functionaliteit hebben veranderd. De tweede test slaagt nu ook. Soortgelijke acties kunnen we verzinnen voor de functies aftrekken, delen en vermenigvuldigen. Bij delen hebben we echter een nieuwe situatie. Er kan een exceptie gaan optreden, namelijk een deling door nul. Hiervoor schrijven we een test:

code 6

CodeSnippet 5

Let vooral op het tweede attribuut [ExpectedException]. Hiermee geven we aan dat wij een exceptie verwachten van het type “DivideByZeroException”. Als we door 0 delen. Na implementatie zal de test dan ook succesvol zijn.

Conclusie: Test Driven Development is meer dan alleen Unit Testing. Zoals in bovenstaand voorbeeld duidelijk wordt, ontstaat de code door het schrijven van tests. Unit testing ondersteunt hierbij. Hierdoor worden de functies veelal kleiner en overzichtelijker, zodat de functies makkelijk te testen blijven. Bugs kunnen worden opgelost door het schrijven van extra tests, met direct de zekerheid dat bestaande code blijft werken. Als er in het begin gelijk met TDD wordt begonnen, is het nauwelijks extra werk, en iedere test die ooit is verzonnen zal tot in de lengte van dagen uitgevoerd worden.

Links:

Sourcecode bij dit artikel: stuur een e-mail naar info@delta-n.nl

Delta-N B.V.

Laan van Waalhaven 287
2497 GL Den Haag

T: 070 - 357 57 00
F: 070 - 357 57 07
E: info@delta-n.nl