Einführung ins Unit-Testen in C# für Anfänger – Setup, Basics und hilfreiche Tools

Alisa Schulz

06/20/2023


Unittests sind für die Entwicklung von Software unerlässlich. Mit ihnen lassen sich Fehler vermeiden, welche sonst erst spät auffallen würden und schwer zu lokalisieren wären. Für C# Entwickler bietet Visual Studio einige Extensions, die uns bei der Erstellung von Unittests unterstützen.

In diesem Blogeintrag führe ich dich durch die wichtigsten Schritte beim Einrichten eines Testprojektes: Anhand eines Beispiels erstelle ich einen einfachen Unittest, gebe einige nützliche Tipps und stelle hilfreiche Tools vor. Die Voraussetzung für leserliche und effektive Unittests ist das die einzelnen Komponenten des Codes unabhängig vom Rest der Software testbar sind.

Wie du deinem Code mithilfe von Interfaces testbar machst, erfährst du in meinem nächsten Blogeintrag „Interfaces für besseres Unittesten“.

Warum sollte man Unittests durchführen?

  • Sicherstellung der Funktionalität von Klassen und Methoden.
  • Vereinfacht die Suche nach Fehlern, dar bestimmte Abschnitte des Codes durch Unittests abgedeckt sind und als Fehlerquelle ausgeschlossen werden können.
  • Nach Anpassungen von Methoden oder Klassen lässt sich einfach und schnell feststellen, ob die Funktionalität noch gegeben ist.

 

Grundlegendes zu Unittests

Beim Erstellen von Unittests ist folgendes zu beachten:

  • Um sinnvolle Unittests erstellen zu können müssen die einzelnen Komponenten unabhängig voneinander testbar sein. Wie Sie die Testbarkeit ihres Codes mit Interfaces gewährleisten, wird im Blogeintrag „Interfaces für besseres Unittesten“ anhand eines Beispiels erklärt.
  • Ein Unittest testet immer genau eine Funktion.
  • Die Eingabeparameter und das zu erzielende Ergebnis müssen bekannt sein, um die Funktion auf ihre Richtigkeit zu überprüfen.
  • Für jede Randbedingung einer Funktion muss ein Unittest erstellt werden um alle möglichen Szenarien, für die diese Funktion verwendet werden kann, abzudecken.

Aufbau eines Unittests

Für das Erstellen von strukturierten und leserlichen Unittests gibt es ein paar Punkte zu beachten:

  • Für jedes Szenario wird eine Testmethode verfasst.
  • Der Name der Testmethode enthält welche Methode getestet wird und worauf sie getestet wird.
  • Der Name der Testmethode endet mit dem Wort „Should“.
  • Beispiel: die Test-Methode für die Funktion Calc(int n1, int n2) welche zwei Nummern addiert könnte Calc::AddTwoNumbersShould() benannt werden
  • Ein Test kann in der Regel in drei Blöcke unterteilt werden
    1. Arrange:
      – Vorbereitung der Input Parameter
      – Festlegen des zu erzielenden Ergebnisses
      – Erstellen von Objekten für den Test
    2. Act:
      – Ausführung der zu testenden Funktion
      – Act besteht meistens nur aus einer einzigen Zeile
    3. Assert:
      – Überprüfen der Ergebnisse
      – Abfragen ob Exceptiones geworfen wurden

Diese Unterteilung lässt deine Tests leserlicher und verständlicher werden, da Sie anhand eines Blickes direkt wissen was die Inputparameter und zu erwarteten Ergebnisse sind (Arrange Block), was getestet wird (Act-Block) und weshalb der Test fehlschlägt (Assert-Block).

 

Beispiel zum Unittesten einer Methode für einen Taschenrechner

Die Folgenden Schritte werden beschrieben

  1. Setup
  2. Die zu testende Klasse: Calculator
  3. Wie legt man ein Test-Projekt an?
  4. Wie legt man eine Test-Klasse an?
  5. Hinzufügen des Verweises auf das zu testende Projekt
  6. Erstellen eines Tests
    a. Was kann alles geprüft werden?
  7. Ausführen eines Tests
    a. mit dem Testexplorer
    b. mit axocover

1. Setup
Im folgenden Beispiel wurde folgendes Setup verwendet

  • Visual Studio 2019
  • NUnitTest: VisualStudio -> Extras -> NuGet package
    o NUnit v3.13.3
    o NUnit3TestAdapter v.4.4.
  • Aoxcover: VisualStudio -> Extras -> Erweiterung und Updates
    o AxoCover v 1.1.7.0

2. Die zu testende Klasse: Calculator
Für dieses Beispiel soll die Methode Calc(int n1, int n2) von der Klasse Calculator getestet werden, welche in Abbildung 1 zu sehen ist. Hierbei beschränken wir uns nur auf die Addition.

Abbildung 1: Zu testende Klasse

3. Test-Projekt anlegen
Legen Sie in der Projektmappe ein zweites Projekt vom Typ „NUnit 3 Unit Test Project“ an.

Abbildung 2: Anlegen eines Testprojektes

4. Erstellen einer Test-Klasse
Erstellen Sie nun in Ihrem neuen Test-Projekt eine neue Testklasse an. Wählen Sie dafür den Typ „NUnit Test Fixture“ aus und benennen Sie diese nach der Klasse oder Funktion, welche Sie testen möchten. Im Folgenden wurde der Name „CalcShould“ verwendet.

Abbildung 3: Anlegen einer Test-Klasse

In der neu erstellten Test Fixture wird Ihnen automatisch eine erste Test-Methode TestMethod(), wie in Abbildung 4, erstellt.

Abbildung 4: Automatisch erstellte Test-Klasse

5. Hinzufügen des Verweises auf das zu testende Projekt
Um nun auf die Klassen aus Ihrem eigentlichen Projekt zugreifen zu können, muss zunächst noch ein Verweis auf Ihr Projekt hinzufügen werden. Machen Sie dafür einen Rechtsklick auf die Verweise Ihres Test-Projekts und wählen Sie „Verweise hinzufügen“. Fügen Sie anschließend Ihr Projekt hinzu.

Abbildung 5: Hinzufügen des Verweises auf das zu testende Projekt

Nun können Sie eine Using-Direktive auf ihr Hauptprojekt in Ihre Test Fixture eintragen. Nun können sie auf Ihre zu testende Klasse zuzugreifen.

Abbildung 6: Hinzufügen der Using-Direkttive auf das zu testende Projekt in der Test-Fixture

6. Erstellen eines Tests
In Abbildung 7 ist eine Testmethode abgebildet, welche Die Methode Calc der Klasse Calculator testet. Hierbei wurde nur die Addition von zwei natürlichen Zahlen getestet.

Arrange:

Im Arrange-Block wird ein Objekt der Klasse Calculator erstellt und die Input Parameter number1 und number2, sowie das zu erwartende Ergebnis resultShould festgelegt.

Act:

Im Act-Block wird die Methode Calc mit den entsprechenden Input Parametern ausgeführt und das Ergebnis in der Variable result gespeichert.

Assert:

Im Assert-Block wird überprüft, ob das Ergebnis result mit dem zu erwartenden Ergebnis resultShould übereinstimmt.

Abbildung 7: Unittest für die Methode Calc für die Addition zweier Integer

Was kann in einem Unittest geprüft werden?
Im Folgenden sind einige hilfreiche Möglichkeiten aufgelistet, um die Klasse Assert in Unittests zu verwenden.

Anwendung von Assert Bedeutung
Assert.That() Is.Equal(var x, var y) Test kann nur bestanden werden, wenn x den gleichen Wert hat wie y
Assert.Fail() Der Test kann nur bestanden werden, wenn der Code Failed bevor er diese Zeile erreicht. Z.B., weil vorher eine unbehandelte Exception geworfen wird
Assert.That(x, Is.GreaterThan(y)); Der Test kann nur bestanden werden wenn x größer ist als y

Weitere Möglichkeiten um Asser. Zu nutzen:
https://docs.nunit.org/articles/nunit/writing-tests/assertions/assertions.html

7. Einen Unittest ausführen
Nun da unser Testprojekt erstellt und der erste Test implementiert ist, müssen wir diesen Test ausführen. Wir können dies mit dem Testexplorer von Visual Studio oder mit dem Package Axocover.

Tests ausführen mit dem Testexplorer

Visual Studio hat einen eigenen Testexplorer, um Tests auszuführen. Um diesen zu nutzen, klicken Sie auf Test -> Fenster -> Testexplorer. Es wird sich der Testexplorer öffnen und alle Tests in Ihrer Projektmappe anzeigen. Mit einem Klick auf „Alle Ausführen“ können Sie all Ihre Tests auf einmal ausführen. Bestandene Tests werden grün markiert.

Abbildung 8: Ausführen des Tests mit dem Testexplorer

Tests ausführen mit Axocover
Axocover erlaubt uns ebenfalls wie der Testexplorer einzelne oder mehrere Tests auf einmal durchzuführen und zeigt uns anschließend die Ergebnisse an

Abbildung 9: Ausführen des Tests mit AxoCover

Es hat jedoch zusätzlich noch die Coverage Funktion. Anstatt die Tests normal auszuführen, können Tests auch „gecovert“ werden. Die ausgewählten Tests werden dann ausgeführt und alle Codezeilen, die für die Tests durchlaufen wurden, werden rechts von der Zeilennummerierung grün markiert.
Alle nicht durchlaufenen Zeilen werden rot markiert. In Abbildung 10 ist zu sehen das alle Zeilen des Tests durchlaufen wurden. Für Entwickler jedoch interessanter ist in Abbildung 11 zu sehen das nur die Zeilen unserer zu testenden Klasse Calculator grün markiert, die auch für den Test durchlaufen wurden. Dort wurde nur der Case der Addition grün markiert und kein weiterer.

Abbildung 10: Coverage der Test-Methode
Abbildung 11: Coverage der getesteten Methode

Dieses feature ist sehr hilfreich, um Buges bei durchgefallen Testläufen zu lokalisieren oder um zu überprüfen, dass die Tests alle möglichen Szenarien einer Methode abdecken. Das Covern dauert jedoch wesentlich länger als ein normaler Testdurchlauf und sollte deswegen gezielt verwendet werden.

 

Fazit

NUnit ermöglicht uns Testprojekte und Test-Fixtures anzulegen, um einzelne Klassen oder Teile eines C#-Projekts zu testen. Zum Testen einer Funktion oder Klasse sollte immer ein Unittest pro Szenario erstellt werden, welcher in die drei Blöcke Arrange, Act und Assert eingeteilt sein sollte.
Im Assert-Block kann mithilfe der Klasse Assert überprüfet werden ob Ergebnisse übereinstimmen, ob Exceptions geworfen wurden und vieles mehr. Zu guter Letzt wurde gezeigt wie mithilfe von Axocover und der Coverage-Funktion überprüft werden kann welche Zeilen unseres Codes für einen Test durchlaufen wurden.


Geschrieben von Alisa Schulz


Weitere Beiträge

  • 29/01/2025
  • Allgemein, Hardware, Testen

Einleitung Um bei der EMV Prüfung für die Zulassung neuer medizintechnischer Geräte das Risiko zu reduzieren machen wir gerne Vortests mit den Geräten in der Prototypen Phase. Aktuell unterstützen ...

Weiterlesen
  • 05/12/2024
  • Allgemein, Systems Engineering, Unternehmen, Veranstaltungen

In einer sich ständig wandelnden Geschäftswelt ist Kreativität ein entscheidender Faktor für den Erfolg. Unternehmen, die innovative Lösungen entwickeln und sich kontinuierlich an neue Herausforderungen anpassen können, haben einen ...

Weiterlesen
  • 12/11/2024
  • Allgemein, Software, Testen, Tools

In sicherheitskritischen Softwareprojekten steht die Qualität der Software an erster Stelle. Besonders bei Klasse-C-Software, die nach strengen Normen wie IEC 62304 (Medizintechnik) zertifiziert werden muss, ist es essenziell, dass ...

Weiterlesen
Cookie-Übersicht

Die Internetseiten der MEDtech Ingenieur GmbH verwenden Cookies. Cookies sind Textdateien, welche über einen Internetbrowser auf einem Computersystem abgelegt und gespeichert werden.

Zahlreiche Internetseiten und Server verwenden Cookies. Viele Cookies enthalten eine sogenannte Cookie-ID. Eine Cookie-ID ist eine eindeutige Kennung des Cookies. Sie besteht aus einer Zeichenfolge, durch welche Internetseiten und Server dem konkreten Internetbrowser zugeordnet werden können, in dem das Cookie gespeichert wurde. Dies ermöglicht es den besuchten Internetseiten und Servern, den individuellen Browser der betroffenen Person von anderen Internetbrowsern, die andere Cookies enthalten, zu unterscheiden. Ein bestimmter Internetbrowser kann über die eindeutige Cookie-ID wiedererkannt und identifiziert werden.

Durch den Einsatz von Cookies kann die MEDtech Ingenieur GmbH den Nutzern dieser Internetseite nutzerfreundlichere Services bereitstellen, die ohne die Cookie-Setzung nicht möglich wären.

Mittels eines Cookies können die Informationen und Angebote auf unserer Internetseite im Sinne des Benutzers optimiert werden. Cookies ermöglichen uns, wie bereits erwähnt, die Benutzer unserer Internetseite wiederzuerkennen. Zweck dieser Wiedererkennung ist es, den Nutzern die Verwendung unserer Internetseite zu erleichtern. Der Benutzer einer Internetseite, die Cookies verwendet, muss beispielsweise nicht bei jedem Besuch der Internetseite erneut seine Zugangsdaten eingeben, weil dies von der Internetseite und dem auf dem Computersystem des Benutzers abgelegten Cookie übernommen wird.

Die betroffene Person kann die Setzung von Cookies durch unsere Internetseite jederzeit mittels einer entsprechenden Einstellung des genutzten Internetbrowsers verhindern und damit der Setzung von Cookies dauerhaft widersprechen. Ferner können bereits gesetzte Cookies jederzeit über einen Internetbrowser oder andere Softwareprogramme gelöscht werden. Dies ist in allen gängigen Internetbrowsern möglich. Deaktiviert die betroffene Person die Setzung von Cookies in dem genutzten Internetbrowser, sind unter Umständen nicht alle Funktionen unserer Internetseite vollumfänglich nutzbar.

Weitere Informationen erhalten Sie in unserer Datenschutzerklärung.

Unbedingt notwendige Cookies

Dieses Cookie wird benötigt, um Ihre Cookie-Einstellungen zu merken und weitere Hauptfunktionen zur Verfügung zu stellen

Um Ihnen eine Auskunft über Ihre gespeicherten personenbezogenen Daten hier (https://medtech-ingenieur.de/gespeicherte-daten-2/) geben zu können, benötigen wir einen Cookie, um Sie bei der Datenabfrage identifizieren zu können. Dieser Cookie muss aus Sicherheitsgründen deshalb aktiviert sein. Ein weiterer Cookie wird gesetzt, um diesen Banner nicht erneut anzeigen zu müssen.

Cookie-Name Beschreibung
PHPSESSID Name: PHP session
Anbieter:
Eigentümer der Webseite (MEDtech Ingenieur)
Zweck:
Wir benötigt, um Sie bei der Anfrage von personenbezogenen Daten identifizieren zu können. Das Cookie wird nur gesetzt, wenn Sie eine Anfrage hier (https://medtech-ingenieur.de/gespeicherte-daten-2/) stellen.
Laufzeit: Sitzungsende
Kategorie: Unbedingt notwendige Cookies
moove_gdpr_popup Name: Cookie-Box Einstellungen
Anbieter:
Eigentümer der Webseite (MEDtech Ingenieur)
Zweck:
Wird benötigt, um Ihre Cookie-Einstellungen zu speichern, um den Cookie-Banner nicht erneut anzeigen zu müssen.
Laufzeit: 1 Jahr
Kategorie: Unbedingt notwendige Cookies
comment_author_9c90e388e3e1be4a6c594fa6ac8a3eec
comment_author_email_9c90e388e3e1be4a6c594fa6ac8a3eec
comment_author_url_9c90e388e3e1be4a6c594fa6ac8a3eec
Name: Kommentar Einstellungen
Anbieter:
Eigentümer der Webseite (MEDtech Ingenieur)
Zweck:
Cookie wird angelegt, wenn Sie ein Kommentar auf MEDtech Ingenieur veröffentlichen wollen, um Sie als Autor identifizieren und den aktuellen Status Ihres Kommentars anzeigen zu können. Das Cookie enthält den angegebenen Namen. Das Cookie wird erst gesetzt, wenn Sie der Speicherung Ihrer personenbezogenen Daten zustimmen.
Laufzeit: 1 Jahr
Kategorie: Unbedingt notwendige Cookies
rmp-rate Name: RMP Rate
Anbieter: Eigentümer der Webseite (MEDtech Ingenieur)
Zweck: Cookie wird angelegt, wenn Sie eine Bewertung eines Blogbeitrags mithilfe des Sternebewertungssystems abgeben. Ihnen wird eine anonymisierte ID zugewiesen, um zu erkennen, ob Sie einen Artikel bereits bewertet haben oder nicht. Das Cookie wird nur verwendet, um zu verhindern, dass mehrfache Bewertung abgegeben werden und erst gesetzt, wenn Sie auf einen Stern klicken.
Laufzeit: 1 Jahr
Kategorie: Unbedingt notwendige Cookies
medtech-download-page Name: Download Page
Anbieter: Eigentümer der Webseite (MEDtech Ingenieur)
Zweck: Cookie wird angelegt, wenn Sie den Landing-Page Prozess erfolgreich durchlaufen haben. Dies geschieht nur, wenn Sie einen Content-Download von unserer Website anstreben.
Laufzeit: 1/2 Jahr
Kategorie: Unbedingt notwendige Cookies