Unit-Tests mit NUnit

In diesem Artikel schreibe ich etwas über das Testen von Software mit Hilfe von NUnit.
NUnit ist ein Open-Source Framework mit welchem man .NET Anwendungen durch Unit-Tests testen kann.

NUnit kann von https://launchpad.net/nunitv2 herunter geladen werden. Die aktuelle Version zum Zeitpunkt des erstellens dieses Artikels ist NUnit-2.5.3.9345.


Nachdem man das MSI-Paket von NUnit installiert hat, steht der Namespace NUnut.Framework neu im GAC zur verfügung. Dieser wird später verwendung finden.

Gehen wir einmal davon aus, das wir eine Software in Schichten schreiben, um eine gewissen Wiederverwendbarkeit dieser „fertigen“ Software sicherstellen zu können.
In diesem Beispiel soll es der Einfachheit halber nur ein simpler Taschenrechner sein, welchen wir in 2 Schichten exemplarisch programmieren.

Die Geschäftslogik steckt dabei in folgender Klasse:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
using System.Collections.Generic;
using System.Text;
 
namespace BuissnessLogic
{
    public class calc
    {
        public calc()
        {
        }
 
        public int add(int a, int b)
        {
            return a + b;
        }
        public int sub(int a, int b)
        {
            return a - b;
        }
        public int mul(int a, int b)
        {
            return a * b;
        }
        public int div(int a, int b)
        {
            return a / b;
        }
    }
}

Das Frontend soll den Programmteil zur verfügung stellen, welchen wir zu Präsentation des Taschenrechners brauchen – deshalb auch Präsentationsschicht genannt.
Hierfür brauchen wir 3 TextBoxen, eine ComboBox und ein Button.
Das ganze soll dann so aussehen, wenn es fertig ist:
2010-03-25_0102

Der Code für das Formlar befindet sich in folgender Klasse:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using BuissnessLogic;
 
namespace calctest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private void btn_erg_Click(object sender, EventArgs e)
        {
            BuissnessLogic.calc calc = new BuissnessLogic.calc();
 
            int iA = Convert.ToInt32(txtA.Text);
            int iB = Convert.ToInt32(txtB.Text);
            int iErg = 0;
            if (comboBox1.Text == "+")
            {
                iErg = calc.add(iA,iB);
            }
            if (comboBox1.Text == "-")
            {
                iErg = calc.sub(iA,iB);
            }
            if (comboBox1.Text == "*")
            {
                iErg = calc.mul(iA,iB);
            }
            if (comboBox1.Text == "/")
            {
                iErg = calc.div(iA,iB);
            }
 
            txtErg.Text = iErg.ToString();
        }
    }
}

Gut. Soviel zum eigentlichen Programmaufbau.
Dieses Programm wollen wir nun mit Hilfe von Unit-Tests testen.

Dafür legt man sich am besten ein neues DLL-Projekt an, in dem man seine Test-Klassen unterbringt.
Dies hat den Vorteil das die Test-Methoden nicht zwingend zusammen mit der eigentlichen Anwendung ausgeliefert werden müssen – und, wenn alles sauber programmiert wurde, kann man dadurch auch gleich die Trennung der schichten prüfen.

In diesem neuen DLL-Projekt haben wir nun die Klasse Class1 in der Datei Class1.cs.
In diese Klasse schreiben wir nun die Test-Methoden.
Vorher referenzieren wir in diesem DLL-Projekt noch die NUnit.Framework DLL aus dem GAC.
Die Test-Klasse kann nun beispielsweise wie folgt aussehen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
 
namespace test
{
    [TestFixture()]
    public class Calculator_UnitTest
    {
        //Instanz der zu testenden Klasse erstellen
        private BuissnessLogic.calc calc = new BuissnessLogic.calc();
 
        [SetUp()]
        public void Init()
        {
            // some code here, that need to be run
        }
 
        [TearDown()]
        public void Clean()
        {
            // code that will be called after each Test case
        }
 
        // Dies ist die erste Test-Methode
        [Test]
        public void Test()
        {
            // Wird wohl in den meisten Fällen wahr sein...
            NUnit.Framework.Assert.IsTrue(true);
        }
    }
}

Was ist nun Wichtig?
Im Prinzip erstmal nur die Test-Methode:

1
2
3
4
5
6
        [Test]
        public void Test()
        {
            // Wird wohl in den meisten Fällen wahr sein...
            NUnit.Framework.Assert.IsTrue(true);
        }

Das „[Test]“ Attribut gibt an, das es sich hierbei um eine Methode zum Testen handelt, welche durch NUnit später angesprochen werden soll.
Das „Assert.IsTrue()“ aus dem NUnit.Framework Namespace prüft ob das result des übergebenen Parameters True ist. Dies ist die vermutlich einfachste Möglichkeit Unit-Tests zu benutzen.
Ist das Result übergebene Result true, war der Test erfolgreich, andernfalls war er es nicht.
Dies wird in der NUnit-GUI auch mit Grünen Haken oder Roten Kreuzen visuell angezeigt.

Hier mal eine Komplette Test-Klasse um die Gäschäftslogik unseres Taschenrechners zu prüfen.
Ich habe bewusst zu jeder Funktion eine Methode geschrieben, welche zutreffen wird – und eine, die es nicht wird.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
 
namespace test
{
    [TestFixture()]
    public class Calculator_UnitTest
    {
        private BuissnessLogic.calc calc = new BuissnessLogic.calc();
 
        [SetUp()]
        public void Init()
        {
            // some code here, that need to be run
        }
 
        [TearDown()]
        public void Clean()
        {
            // code that will be called after each Test case
        }
 
        [Test]
        public void Test()
        {
            NUnit.Framework.Assert.IsTrue(true);
        }
 
        #region Addition
        [Test]
        public void Test_OK_Addition()
        {
            int result = calc.add(2, 2);
            NUnit.Framework.Assert.IsTrue(result == 4);
        }
        [Test]
        public void Test_NOK_Addition()
        {
            int result = calc.add(2, 2);
            NUnit.Framework.Assert.IsTrue(result == 3);
        }
        #endregion 
 
        #region  Subtraktion
        [Test]
        public void Test_OK_Subtraktion()
        {
            int result = calc.sub(2, 2);
            NUnit.Framework.Assert.IsTrue(result == 0);
        }
        [Test]
        public void Test_NOK_Subtraktion()
        {
            int result = calc.sub(2, 2);
            NUnit.Framework.Assert.IsTrue(result == 3);
        }
        #endregion
 
        #region  Test - Multiplikation
        [Test]
        public void Test_OK_Multiplikation()
        {
            int result = calc.mul(2, 2);
            NUnit.Framework.Assert.IsTrue(result == 4);
        }
        [Test]
        public void Test_NOK_Multiplikation()
        {
            int result = calc.mul(2, 2);
            NUnit.Framework.Assert.IsTrue(result == 3);
        }
        #endregion
 
        #region  Test - Division
        [Test]
        public void Test_OK_Division()
        {
            int result = calc.div(2, 2);
            NUnit.Framework.Assert.IsTrue(result == 1);
        }
        [Test]
        public void Test_NOK_Division()
        {
            int result = calc.div(2, 2);
            NUnit.Framework.Assert.IsTrue(result == 3);
        }
        #endregion
    }
}

Nach dem wir das Komplette Projekt incl Test-DLL-Projekt und Test-Klasse kompiliert haben können wir die Test-DLL nun zum testen mit NUnit verwenden.
Dazu benutzen wir die NUnit GUI, welche wir mit dem NUnit MSI-Paket installiert haben.
Dieses findet sich unter den Programmen im Ordner „NUnit 2.5.3“ oder in „C:\Programme\NUnit 2.5.3\bin\net-2.0\“ mit dem Namen „NUnit.exe“ wieder.

Haben wir die NUnit-GUI aufgerufen, so erhalten wir erst einmal ein leeres GUI Fenster.
Unter „File->new project“ legen wir ein neues Projekt an.
Die Prokelt-Datei, welche schon den Namen project1.nunit vorgegeben hat, legen wir in den bin\debug\ Ordner der Test-DLL unseres Taschenrechner-Projektes.
Ich hatte diverse Probleme mit NUnit, wenn die zu testende Assembly nicht in dem selben Ordner lag wie die NUnit-Projektdatei.
Nun müssen wir dem Projekt die zu testende Assemby hinzufügen.
Hierzu gehen wir auf „Project->Add Assembly…“ und wählen dort die test.dll von unserem Test-Projekt aus.
NUnit läd nun diese DLL und listet alle Testmethoden auf.

nunitgui_vortest

Diese Test-Methoden kann man nun einzeln testen, oder alle zusammen auf einmal testen.
Dazu einfach nur oben auf „Run“ klicken. Nun werden alle verfügbaren Tests durchgetestet und anschlißend wird das Ergebnis der Tests präsentiert.

Für unsere Test-DLL würde dies wie folgt aussehen:
nunitgui_nachtest

Alle Tests welche true ergeben sind erfolgreich gewesen und wurden visuell grün dargestellt.
Alle Tests, welche nicht erfolgreich waren, werden visuell rot dargestellt.

Ja… sehr viel mehr gibt es über das Unit-Testing eigentlich für den Anfang nicht zu sagen 🙂

2 Responses to Unit-Tests mit NUnit

  1.  

    Omg … der Sven schreibt tests 🙂

    Hätte nicht erwartet das noch zu meinen lebzeiten zu sehen 🙂

    Krank ? Fieber ?

    Was kommt als nächstes ? testgetriebene Entwicklung ? 🙂

  2. Jetzt mach mich doch nicht gleich in der öffentlichkeit so schlecht hier 😉

    Ich bin weder Krank, noch habe ich Fieber.
    Aber ich hatte diese Woche Urlaub und deswegen genug Zeit um mich damit mal auseinander zu setzen 😉

    Testdriven Development – hört sich doch gar nicht mal so schlecht an-
    Vielleicht setze ich das mit auf meine ToDo-Liste 😀

     

leave your comment

*

Unterstütze den Frickelblog!