Unit testen in .Net

Ontwikkelaars maken al jaren gebruik van unit testen, maar meestal nadat de programmacode is ontworpen en geschreven. Je kunt je voorstellen dat het schrijven van een test achteraf niet eenvoudig is. Het wordt dan ook vaak achterwege gelaten. Het testen van de code gebeurt dan meer tijdens gebruikerstesten.

Test-driven development (TDD) probeert dit probleem op te lossen en zorgt er voor dat de geschreven programmacode van een hogere kwaliteit is. De testen worden in dit geval geschreven vóór de code. Dit artikel, het eerste deel van een serie van twee, beschrijft hoe je je programmacode zo kunt schrijven dat het eenvoudiger is om er (automatische) unit tests mee uit te voeren.

Wat zijn unit testen?

Een unit test wordt vaak omschreven als een programma dat bedoeld is om een batch te draaien om daarin classes te testen. Een dergelijk programma stuurt de class een vast bericht en gaat na of het verwachte antwoord terugkomt. In de praktijk komt het er op neer, dat je een programma schrijft dat de publieke interfaces van de classes in je applicatie test. Let er op dat dit dus niet een functionaliteitstest of acceptatietest is. Het gaat er puur om dat de methoden in je class dat doen wat je ervan verwacht.

Je schrijft een programma dat de publieke interfaces van de classes test

Het kan een behoorlijke taak zijn om dit goed te doen. Je moet eerst bepalen welke tools je gebruikt om je tests te creëren. In het verleden zijn er grote testsuites beschikbaar gekomen met ingewikkelde scripts die ideaal waren voor gespecialiseerde Quality Assurance (QA) teams. Deze suites zijn echter minder geschikt voor unit testen. Het ligt voor de gemiddelde programmeur veel meer voor de hand om testen te ontwikkelen die gebruik maken van de zelfde taal en IDE als waar ze de applicatie in ontwikkelen.

Veel moderne unit test frameworks zijn gebaseerd op het framework van Kent Beck voor het eerste XP project, genaamd Chrysler C3. Dit framework is geschreven in Smalltalk en bestaat nog steeds, alhoewel er in de loop van de tijd meerdere revisies zijn geweest. Later is dit framework geport naar Java en werd toen JUnit genoemd. Daarna zijn er implementaties gekomen in C++, VB, Python, Perl, etc.

Het NUnit Test Framework

NUnit is een unit-test framework voor alle .NET talen. Versie 2.0 is volledig nieuw ontworpen om gebruik te maken van de mogelijkheden van het .NET Framework. De broncode in C# is voor iedereen beschikbaar, omdat het een open source project is. NUnit 2.0 is anders dan haar voorgangers. Deze voorgangers maakten gebruik van base classes voor de hiervan afgeleide test classes. Er was geen andere manier om het voor elkaar te krijgen. Helaas betekende dat ook dat het restricties opwierp voor het bouwen van de testcode, omdat veel talen (zoals Java en C#) alleen single inheritance ondersteunen. Het opbouwen van de testcode was daardoor lastig en leidde al snel tot complexe class-hiërarchieën.

De broncode in C# is voor iedereen beschikbaar, omdat het een open source project is

Het .NET Framework introduceerde een nieuw programmeerconcept waarmee dit probleem kon worden opgelost: attributen. Met attributen ben je in staat metadata aan de code toe te voegen. Meestal hebben deze attributen geen invloed op de wijze waarop de code zelf functioneert, maar het biedt extra informatie over de geschreven programmacode. Vaak gebruik je attributen om je code te beschrijven, maar het kan ook gebruikt worden om informatie over de assembly te geven aan een programma dat deze assembly nooit eerder gezien of gebruikt heeft.

Dat is precies de manier waarop NUnit werkt. De Test Runner applicatie doorzoekt je gecompileerde code naar attributen die vertellen welke classes en methoden testclasses zijn. Vervolgens wordt reflection gebruikt om deze methoden uit te voeren. Je hoeft enkel gebruik te maken van de juiste attributen.

NUnit levert een reeks van attributen die je kunt gebruiken voor het maken van een unit test. Met deze attributen definieer je test fixtures, test methoden, setup en teardown methoden. Er zijn ook attributen voor het aangeven van de verwachtte exceptions of om een bepaalde test over te slaan.

TestFixture Attribuut

Het TestFixture attribuut is bedoeld om aan te geven dat een class test methoden bevat. Wanneer je dit attribuut toevoegt aan een class in je project, zal de Test Runner deze class scannen voor test methoden.

Het TestFixture attribuut is bedoeld om aan te geven dat een class test methoden bevat

In de volgende paragrafen laten we de werking van NUnit zien. Om de voorbeeld zelf te kunnen proberen moet je natuurlijk beschikken over NUnit. Versie 2.1 (op dit moment de meest recente) is te downloaden via www.nunit.org. Omdat NUnit een open source project is, kun je de tools gratis gebruiken.

In het volgende voorbeeld zie je hoe je dit attribuut gebruikt. De gebruikte code is VB.NET, maar C# is natuurlijk ook mogelijk. Na het installeren van NUnit kun je in je .NET project referenties toevoegen voor de NUnit assemblies.

Imports System

Imports NUnit.Framework

<TestFixture()> _

Public Class UnitTests

End Class

De enige voorwaarde voor classes die het TestFixture attribuut gebruiken, is dat ze een publieke default constructor moeten hebben (of geen constructor, dat is het zelfde).

Test Attribuut

Het Test attribuut wordt gebruikt om aan te geven dat een methode in een test fixture gestart moet worden door de Test Runner applicatie. De methode moet publiek zijn en niets terug geven (een Sub in VB.NET, function void in C#). Ook mag de methode geen parameters hebben, anders wordt de methode niet getoond in de Test Runner GUI en zal ook niet aangeroepen worden bij het starten van de TestFixture.

De volgende code illustreert het gebruik van het Test attribuut.

Imports System

Imports NUnit.Framework

<TestFixture()> _

Public Class UnitTests

  <Test()> _

  Public Sub TestA()

    'doe iets

  End Sub

End Class

Je kunt in de constructor van het Test attribuut overigens ook een omschrijving meegeven, net als bij het TestFixture attribuut.

SetUp en TearDown attributen

Het komt voor dat je bij het samenstellen van de Unit Tests eerst bepaalde handelingen moet uitvoeren voor en na het draaien van een test. Je kunt een private methode creëren en die aanroepen vanuit iedere testmethode, maar je kunt ook Setup en TearDown attributen gebruiken. Deze attributen geven aan dat een methode moet worden gestart vóór en ná ieder testmethode in de Test Fixture. Het meest voor de handliggende gebruik van deze attributen is bij het creëren van objecten waar de testmethode van afhankelijk is (database connecties bijvoorbeeld).

In het volgende voorbeeld zie je hoe je SetUp en TearDown gebruikt.

Imports System

Imports NUnit.Framework

<TestFixture()> _

Public Class UnitTests

  Private _DbConn As String

  <SetUp()> _

  Public Sub SetupTest()

    _DbConn = "server=(local);password=;user id=sa;"

  End Sub

  <TearDown()> _

  Public Sub TeardownTest()

    _DbConn = ""

  End Sub

  <Test()> _

  Public Sub TestA()

    'doe iets

   End Sub

End Class

ExpectedException attribuut

Het komt ook voor dat je een situatie wilt creëren waar zeker een exception optreedt. Dat is het meest eenvoudig te realiseren via het ExpectedException attribuut, zoals in het volgende voorbeeld.

Imports System

Imports NUnit.Framework

<TestFixture()> _

Public Class UnitTests

  <Test(), _

    ExpectedException(GetType(InvalidCastException))>_

  Public Sub TestA()

    'doe iets

  End Sub

End Class

Zodra deze code wordt uitgevoerd,zal de test alleen slagen wanneer er een InvalidCastException wordt opgeworpen. Je kunt, zoals je ziet, meerdere attributen achter elkaar plaatsen (onder elkaar in C#) om meerdere exception-types op te geven. Probeer dat echter zo min mogelijk te doen. Een test is er veelal voor bedoeld om één ding te testen. Houdt er ook rekening mee dat het attribuut niet op geërfde typen controleert. Als er een exception optreedt die afgeleid van een InvalidCastException, dan faalt de test toch.

Een test is er veelal voor bedoeld om één ding te testen

Ignore attribuut

Je zult dit attribuut waarschijnlijk niet zo veel gebruiken, maar als je het nodig hebt, is het toch handig. Als je wilt dat een bepaalde test niet moet lopen, dan gebruik je het Ignore attribuut, zoals in onderstaand voorbeeld.

_

Public Sub TestToIgnore()

End Sub

Het is beter om dit attribuut te gebruiken in plaats van het ‘uit-commentariëren’ van de methode. Op deze manier blijft de test nog steeds beschikbaar, en wordt je er in de Test Runner output toch aan herinnerd.

NUnit Assertion Class

Naast de attributen die je kunt gebruiken om testen in je code te identificeren, bevat NUnit nog een belangrijke class. Dit is de Assertion class die je statische methoden geeft die je kunt gebruiken in je testmethoden om na te gaan dat hetgeen is gebeurd ook het gewenste gedrag is geweest. Een voorbeeld maakt het wellicht wat duidelijker.

_

Public Sub TestB()

  Dim user As String = "piet puk"

  Assertion.AssertEquals("piet puk", user)

End Sub

Het is niet het mooiste staaltje code, maar je begrijpt waarschijnlijk wel wat de bedoeling is. Op ieder moment in de testcode kan je met Assertion-methode bekijken wat de state is van een variabele.

Tests uitvoeren

Nu dat we de beginselen kennen van de testcode, moeten we nu weten hoe we de testen kunnen uitvoeren. Dat is eigenlijk vrij eenvoudig. NUnit beschikt over twee Test Runner applicaties. een Windows applicatie en een Console versie. Beide zijn in staat om XML output te generen. Vooral de consoleversie is handig wanneer je nachtelijke testbatches wilt draaien op de geschreven programmacode.

Om de Windows versie te gebruiken start je de applicatie (na installatie terug te vinden via Start – All Programs). In het programma open je de assembly (dll of exe) die je Test Fixtures bevat. Je krijgt een boomstructuur te zien van de classes en methodes in de assembly. Je kunt individuele methoden en classes testen, maar ook alle tests door op Run te klikken.

Er zijn situaties, bijvoorbeeld wanneer je geautomatiseerde buildscripts hebt gemaakt (via NAnt), waarbij testen via een GUI niet praktisch is. Hiervoor is de NUnit console applicatie meer geschikt. Deze genereert een XML bestand die je met XSLT kunt transformeren naar HTML of een ander formaat zodat de testresultaten getoond en afgedrukt kunnen worden. De NUnit documentatie geeft meer uitleg over het gebruik van de console applicatie.

NUnit beschikt over twee Test Runner applicaties. een Windows applicatie en een Console versie

Test-Driven Development

Oké, nu weet je hoe je unit tests moet schrijven, toch? Helaas is testen net als programmeren. Alleen de syntax kennen is niet voldoende. Kennis en vooral kunde van testmethoden en -technieken zijn essentieel om betrouwbare software te schrijven. Test-Driven Development (TDD) maakt daar een onderdeel van uit. Als je niet bekend bent met TDD komt het je misschien op het eerste gezicht vreemd over.

Er wordt geen regel code geschreven tot je een test hebt die mislukt

De traditionele manier van software ontwikkeling begint met het ontwerp van je classes, het schrijven van de implementatie en vervolgens het testen. Wanneer testen je uitgangspunt is, is de aanpak anders. In plaats van het ontwerpen van een component, het schrijven van de programmacode en daarna testen, draaien we de zaak namelijk om. Er wordt geen regel code geschreven tot je een test hebt die mislukt. In dit geval gaat het schrijven van je programma als volgt:

1.           schrijf een test

2.           draai de test; de compilatie zal mislukken, want de code die je test aanspreekt zal niet bestaan (derhalve mislukt ook de test).

3.           schrijf de kale structuur van je class om te testcode te kunnen compileren.

4.           draai de test; de test zal mislukken (als dat niet zo is, is de test niet goed).

5.           implementeer de code om de test succesvol te doorstaan.

6.           draai de test; nu slaagt de test (ga anders terug naar stap 5).

7.           ga verder met stap 1.

Als je bezig bent met stap 5, schrijf je code volgens een proces dat ‘Coding by Intention’ heet. Je programmeert dan top-down in plaats van bottom-up. Je denkt niet “ik heb deze class met deze methodes nodig”, maar je schrijft code voordat de class die je nodig hebt bestaat. Het compileren van de code zal dan mislukken, want de compiler kan de class niet vinden. Op zich is dat goed, want een mislukte compilatie geldt als een mislukte test.

Wanneer je op deze manier programmeert, beschrijf je de bedoeling van de code die je nodig hebt. Dit zorgt niet alleen voor goed geteste code, maar het is vaak leesbaarder en beter te debuggen. Ook het ontwerp verbetert. Bij traditionele softwareontwikkeling wordt getest of een bestaand stuk code correct geschreven was. Bij TDD worden testen gebruikt om het gedrag van een class te definiëren voordat je hem schrijft. Dat is niet per sé makkelijker, maar wel netter.

Als je bekend bent met Extreme Programming, dan kun je dit zien als een review. Een voorbeeld zal het e.e.a. verduidelijken. Stel dat we een applicatie hebben die in staat is om geld op te nemen van en te storten op een bankrekening. Voordat we een BankRekening class maken, schrijven we eerst een test. Deze test ziet er als volgt uit:

:="Storten op rekening")> _

Public Sub BankRekeningTest()

  Dim br As New BankRekening

  br.Stort(25.0)

  br.Stort(100.0)

  Assertion.AssertEquals(125.0, br.Saldo)

End Sub

Deze code zal niet compileren, want de BankRekening class bestaat niet. Dit is typisch een vorm van Test-Driven Development. Schrijf geen code tot je een test hebt die mislukt. Het niet kunnen compileren geldt ook als een mislukte test.

Dan schrijven we een BankRekening class die in ieder geval code bevat om de test te laten compileren.

Public Class BankRekening

  Public Saldo As Double

  Public Sub Stort(ByVal bedrag As Double)

  End Sub

End Class

De code compileert nu prima, dus we kunnen de test starten. De test mislukt met de volgende reden:

UnitTests.UnitTests.BankRekeningTest:

  expected:<125>
  but was:<0>

 We moeten dus de class uitbreiden om er voor te zorgen dat de test wel goed verloopt.

Public Class BankRekening

  Private _saldo As Double

  Public Sub Stort(ByVal bedrag As Double)

    _saldo += bedrag

  End Sub

  Public ReadOnly Property Saldo() As Double

    Get

      Return _saldo

    End Get

  End Property

End Class

Deze keer gaat de test wel goed.

Conclusies

Serieuze ontwikkelaars schrijven betrouwbare programmacode. Unit testen zijn een belangrijk instrument om te bepalen of de code inderdaad doet wat ervan wordt verwacht. Test-Driven Development is een methode die, gebruikmakend van unit testen, een ontwikkelmethode voorstelt waarmee eerste de test en dan pas de code wordt geschreven. Op deze manier is de programmacode leesbaarder, beter te debuggen en is ook het ontwerp potentieel beter.

De open-source tool NUnit maakt het de ontwikkelaar makkelijk om TDD als methodiek te hanteren, en op zijn minst het unit testen van zijn componenten te automatiseren.

In het volgende artikel over unit testen gaan we in op het gebruik van nepobjecten en het testen van de verschillende lagen (data, business en presentatie) in een applicatie.

Meer informatie

  • http://www.nunit.org/default.htm

  • http://www.msdnaa.net/Resources/display.aspx?ResID=2365

  • http://www.devcity.net/net/article.aspx?alias=xprogramming

  • http://www.tangent-studios.com/programming/csharp/NUnit2Tut/NUnitV2Tut.htm



  • Commentaar van anderen:
    bags op 9-7-2010 om 9:46
    As we all know, now Tag Heuer watches common replication, not only for the common people U-boat watches for some pop stars.Miu Miu replica handbags is imitated handbags has its own advantages to the so-called rich people are Mulberry replica handbags like them. So what? You will become a trend of reproductions, A.Lange & Sohne watches, fashion.Are you interested in buying a Audemars Piguet watches or gucci Replica handbags copy copies? You know, the best way is to buy you buy Dior replica handbags? A few years ago, when people want to buy something,Dolce & Gabbana replica handbags they had to drive to Louis Vuitton handbagsthe local shop or the city center recently get what they want.
    replica handbags op 16-7-2010 om 9:54
    Actually, jimmy choo replicathere are too many brands like Designer HandbagsLouis Vuittion, Balenciaga, Gucci, versace replica handbags, Miu Miu, Fendi, Versace,swiss watches Kooba and so on, how designer watchescould you find the right style forGlashutte watches you? My suggestion is to considerreplica handbags quality over quantity and burberry handbagskeep in mind that a high qualityChloe handbags designer bag will go with youPatek Philippe for sale for years as a bottega veneta handbagsfaithful friendRado for sale.As mentioned above, choosing the rightRolex for sale designer handbags is something Glashutte for saleof art, which reflects your sense of stylejimmy choo replica handbags, taste, and even more, it’s signal of your level of swiss watchessophistication. Breitling replicaPretty girls will always have differentLouis Vuitton replica handbags designer handbags to fit theirChloe handbags needs for differentPatek Philippe for sale occasions. They believe high authentic fendi handbagsquality designer handbagsFranck Muller for sale are good investments.
    fasfaf fasfafaf op 28-7-2010 om 4:51
    Tiffany jewelry manufacturers directory,cheap jewelry - lots of registered importers and exporters. Cheap tiffany jewelry manufacturers, Tiffany & co jewelry suppliers, tiffany jewelry wholesales, Tiffany Watches,exporters, sellers, traders and gold tiffany jewelry Distributors from China and around the world at www.goldtiffanyjewelry.com Tiffany jewelry exporters, Tiffany Accessories, Tiffany Bangles, Tiffany Bracelet, Discont Tiffany Bracelet, Discount Tiffany Cufflinks, Fashion Tiffany Earring, Tiffany Necklaces , Discount Tiffany Necklaces, Tiffany Rings, Tiffany Watches
    fasfaf fasfafaf op 28-7-2010 om 4:52
    Tiffany jewelry manufacturers directory,cheap jewelry - lots of registered importers and exporters. Cheap tiffany jewelry manufacturers, Tiffany & co jewelry suppliers, tiffany jewelry wholesales, Tiffany Watches,exporters, sellers, traders and gold tiffany jewelry Distributors from China and around the world at www.goldtiffanyjewelry.com Tiffany jewelry exporters, Tiffany Accessories, Tiffany Bangles, Tiffany Bracelet, Discont Tiffany Bracelet, Discount Tiffany Cufflinks, Fashion Tiffany Earring, Tiffany Necklaces , Discount Tiffany Necklaces, Tiffany Rings, Tiffany Watches
    fake watch op 9-8-2010 om 9:54
    Hello,FIFA World Cup South Africa we offer Omega watches With Best Quality,at watch shop, you can buy fake watch Our gaqoniag fake rolex watches are unique in the trade for the semblance to the real thing. buy fake watchesguaranteed! Replica Watches Store provides the best fake breitling watches to our customers at the lowest prices. This best fake chanel watches is known for Men and Ladies, as replica tag heuer Formula,Monaco, fake rolex are the best solution if you cannot afford to purchase so expensive original Rolex and rolex fake watches Now please come in!Such a surprise wait for you. gucci watches gucci ladies watches Chanel Watches gucci mens watches Fendi Watches The 18th Golden Rooster Hundred Flowers Film Festival rolex Submariner appeared replica watches in rolex day date replica an replica rolex watches almost record low number of stars rolex air king in the replica tag heuer embarrassing bmw watches situation rolex milgauss in the evening of rolex oyster watch the replica breitling watches 17th over. Film Festival has fake breitling watches come replica watches to an end, untreated illnesses and new diseases have added. In selecting the host city, the mens omega watches film rolex watches festival omega watches sale organized replica breitling by fake cartier watch the replica breitling watches meaning of star attitude towards domestic replica corum watches film replica tag heuer festival and chopard watches replica many other d&g women watches aspects of the problems left corum watches over fake rolex watches need to think deeply of domestic film. blancpain watches esprit watches raymond weil watches sinn watches
    zero op 11-8-2010 om 12:31
    Did you need a Used Stationary Bikes? There are many types of Used Stationary Bikes design to suit the needs of many health conscious people. You need to look at a number of important things to make sure it is the right Used Stationary Bikes for you before you buying. The first thing you need to consider when buying an Used Stationary Bikes is what sort you need. The next thing you need to consider is the stability of the Used Stationary Bikes. Find More Information at Used Stationary Bikes Eiknujomorp
    Administrator op 21-8-2010 om 11:15
    When it comes to replica Marc Jacobos handbags, Europe has a lot to offer. One of its famous exported designer brands is fendi replica handbags. This brand is popular among the celebrities and the wealthy women all over the world. Aside from indicating status, owning a Burberry thomaswylde replica handbags denotes great sense of fashion. Real Burberry christian Dior replica handbags stand for luxury and glamour. In the past, this brand is recognized for being a great outdoor Kooba replica handbags. But recently, it is popular for its classic and unique designs. If you want to shop for authentic replica Celine handbags, their prices range from $600 to $1000. But if you want to avail of bargain deals, you can opt for replica armani replica The best place to find a replica Chloe handbags is over at the internet where you can get one for a price which is lower than $300. One of the online sites which sell designer brand Marni replica is discount authentic designer handbags. A cheap Valentino handbags is widely known for its high quality materials. You can take a pick from quilted leather, transparent vinyl, and calf leather. On the other hand, its design makes this brand one of the most sought-after replica Louis Vuitton handbags. This is due to its unique checkered or plaid pattern. When choosing from the Valentino replica selections of replica Yves Saint Laurent handbags, you are provided with various diversified leather materials. Your options are comprised of ostrich skin, anya Hindmarch handbagsJimmy Choo replica handbagschloe replica handbagscoach replica handbags, lizard skin, crocodile skin, snake skin, togo, and box calf. You can also choose from different classic colors such as tan, reddish brown, dark brown, and cream. The giverchy replica handbags of Marni replica handbags come in plaid or basic designs. Not only this, you can even add your own cheap Yves Saint Laurent handbags ideas. If there is something you want to add to a bottega Veneta replica of your choice, you can simply tell the site about it and they will customize the hermes handbags for you. hermes replica sells cheap Cartier handbags for low prices. You can shop for a replica Armani handbags without having to spend as much as $500. When you opt for the replica designer replica handbags of this online site, you will be able to avail of a discount. This is something which you cannot get when buying from boutiques. While there are some women who have been able to buy their own gucci handbags for a lesser cost, they are not sure whether this Miumiu replica handbags is the real thing or not. But when you shop at chanel replica handbags, you won’t have to worry about fake cheap Marc Jacobos handbags. You will be provided with burberry replica handbags which are made from quality materials. Aside from a replica Burberry cheap Ferragamo handbags, Kooba replica also sells other Burberry items. These include purses, replica Versace handbags, and wallets. All of these are offered at discounted prices, letting you have the chance to buy as much as your budget permits. If you want to browse through the selections of Mulberry handbags at cheap Burberry handbags, all you have to do is check out its website. You will be provided with images of its replica Valentino handbags, along with the price of that certain product.
    GHT op 24-8-2010 om 5:26
    LRH20100824

    Do you wish to select an ideal and stylish Designer Handbags? Do you want perfection in every item that you use? Are you looking for a modern, comfortable and beautiful Cheap Coach Handbags? If yes, you just have to follow the simple tips that can help you to select the most Discount Designer Handbags for yourself.

    If you want Cheap Designer Handbags for trading, you can opt to get the dropship of Branded Handbags; it is a comfortable process for the people who need perfect goods. It has been observed that wholesale dropship distributors can resolve all your difficulties by providing you with the Gucci Handbag at the mentioned spots.

    Geef feedback:

    CAPTCHA image
    Vul de bovenstaande code hieronder in
    Verzend Commentaar