
Unittests prüfen einzelne Einheiten einer Anwendung isoliert und in Millisekunden – ohne Datenbank oder Infrastruktur. Der Beitrag zeigt, wie das AAA-Pattern (Arrange, Act, Assert) Tests lesbar und diagnostizierbar hält, und ordnet die Test Doubles ein: Dummy, Stub, Spy, Mock und Fake. Ein Fokus liegt auf typischen Anti-Patterns wie Über-Mocking, Brittle Tests, Assertion Roulette, Mystery Guest und Test-Logik im Testcode. Zudem wird eingeordnet, warum Code-Coverage ein hilfreicher Indikator, aber kein Qualitätsbeweis ist. Fazit: Gut geschriebene Unittests verbessern das Design, sichern Refactorings ab und decken Fehlimplementierungen frühzeitig auf.
Ein Unittest ist ein automatisierter Test, der eine einzelne, in sich abgeschlossene Einheit des Systems, wie z. B. eine Methode, isoliert von ihren Abhängigkeiten verifiziert. Er läuft in Millisekunden, benötigt keine Datenbank, keinen Netzwerkzugriff und keine laufende Infrastruktur.
Gut geschriebene Unittests liefern folgende Vorteile:
BorrowBookAsync_BookNotAvailable_ThrowsBookNotAvailableException beschreiben präzise, was in dem Szenario passieren soll.
Jeder Unittest lässt sich in drei Phasen gliedern. Diese Trennung macht die Tests lesbarer und erleichtert die Diagnose bei einem Fehlschlag.
Ein gutes Beispiel für AAA:
1[TestMethod]
2public void Create_ValidInputs_SetsDueDate14DaysLater()
3{
4 // Arrange
5 var now = new DateTimeOffset(2026, 1, 15, 12, 0, 0, TimeSpan.Zero);
6 var expectedDueDate = now.AddDays(14);
7
8 // Act
9 var loan = Loan.Create(Guid.NewGuid(), Guid.NewGuid(), now);
10
11 // Assert
12 loan.DueDate.ShouldBe(expectedDueDate);
13}
Ein schlechtes Beispiel für AAA:
1[TestMethod]
2public void TestLoan()
3{
4 var loan = Loan.Create(Guid.NewGuid(), Guid.NewGuid(),
5 DateTimeOffset.UtcNow); // nicht deterministisch!
6 Assert.IsNotNull(loan);
7 Assert.AreEqual(loan.BorrowedAt.AddDays(14), loan.DueDate);
8 Assert.IsNull(loan.ReturnedAt);
9 // was wird hier eigentlich getestet?
10}
Wenn jede Methode eines Stubs verifiziert wird, testet man nicht mehr das einzelne Verhalten, sondern die Implementierung des Systems.
Beispiel:
1// Zu viel: Implementation Detail
2await _books.Received(1).GetByIdAsync(book.Id); // interne Abfrage
3await _books.Received(1).UpdateAsync(book); // das ist relevant!
4// Nur fachlich wichtige Interactions verifizieren.
Tests, die sich auf die interne Struktur (private Felder) beziehen, brechen beim Refactoring. Getestet werden sollte das Verhalten und nicht die Implementierung.
Ein Test mit zwölf Asserts zeigt bei einem Fehlschlag nur, welcher Assert zuerst fehlschlägt. Daher sollte der Test in diesem Fall aufgeteilt werden.
Die Daten kommen aus einer externen Datei, einer globalen Variable oder einer Datenbank. Das macht es dem Leser des Tests schwerer, nachzuvollziehen, warum ein bestimmter Wert verwendet wird.
Kontrollfluss im Test kann dazu führen, dass der Test selbst Fehler enthält. Tests sollten einfach gehalten werden. Verschiedene Varianten lassen sich über DataRow abbilden.
Beispiel:
1// NICHT SO
2
3[TestMethod]
4
5public void TestTitles()
6
7{
8
9 foreach (var title in new[] { null, "", " " })
10
11 {
12
13 // Test-Logik = potenzielle Bugs im Test selbst!
14
15 }
16
17}
// SO
[DataTestMethod]
[DataRow(null)]
[DataRow("")]
[DataRow(" ")]
public void Constructor_EmptyTitle_ThrowsArgumentException(string? title) { ... }
Code-Coverage gibt an, welcher Anteil des Programmcodes während der Tests ausgeführt wurde, sagt aber nichts über die Qualität der Tests aus.
Was Code-Coverage aussagt: welcher Code überhaupt nicht getestet wurde.
Was Code-Coverage nicht aussagt: ob die Tests sinnvoll sind, ob die richtigen Szenarien abgedeckt sind oder ob die Assertions korrekt sind. Ein Coverage-Bericht kann jedoch beim Erkennen von komplett ungetesteten Klassen oder Pfaden helfen.
Unittests sind ein wichtiger Bestandteil der heutigen Softwareentwicklung. Durch sie lassen sich Fehlimplementierungen, die z. B. bestehendem Code schaden würden, schneller aufdecken.

Praxiswissen, Tipps und Neuigkeiten für den Mittelstand: kompakt und ohne Spam. Abmelden jederzeit möglich.
Praxiswissen, Tipps und Neuigkeiten für den Mittelstand: kompakt und ohne Spam. Abmelden jederzeit möglich.