Für Testeigenschaften gibt es eine brauchbare Merkhilfe. Sie beschreibt fünf Eigenschaften, deren Fehlen jeweils eine konkrete Krankheit erzeugt.
Fast — schnell
Eine Testsuite, die zehn Minuten braucht, wird nicht mehr vor jedem Commit ausgeführt. Und eine Suite, die nicht ausgeführt wird, sichert nichts ab.
Das ist keine Frage der Disziplin, sondern der Rückkopplung: Unter fünf Sekunden lässt man sie nebenbei laufen, über einer Minute wartet man auf den Build-Server.
Der häufigste Grund für langsame Tests ist ein Zugriff, der nicht in einen Unit-Test gehört — echte Datenbank, echtes Netzwerk, echtes Dateisystem, echtes Thread.Sleep.
Independent — unabhängig
Kein Test darf von einem anderen abhängen. Das klingt selbstverständlich und wird trotzdem regelmässig verletzt — meistens über geteilten Zustand:
public class KundenTests
{
private static readonly List<Kunde> Kunden = new List<Kunde>(); // static!
[Fact]
public void Anlegen_FuegtKundenHinzu()
{
Kunden.Add(new Kunde("Anna"));
Assert.Single(Kunden); // grün — solange dieser Test zuerst läuft
}
}Das Schadensbild
Tests laufen einzeln grün und zusammen rot. Oder sie laufen grün, bis der Runner die Reihenfolge ändert — und xUnit ordnet die Reihenfolge ausdrücklich nicht zu. Dann sucht jemand einen Fehler, den es im Produktionscode gar nicht gibt.
Repeatable — wiederholbar
Derselbe Test muss auf jedem Rechner, zu jeder Zeit dasselbe Ergebnis liefern. Die drei üblichen Störquellen:
// 1. Zeit
Assert.True(gutschein.IstGueltig()); // gilt bis 30.06. — ab dem 01.07. rot
// 2. Zufall
var id = Guid.NewGuid(); // nicht reproduzierbar
// 3. Kultur
Assert.Equal("1'234.50", betrag.ToString("N2")); // je nach Systemkultur andersAlle drei haben dieselbe Lösung: Das Unberechenbare wird hereingereicht. Für die Zeit ist das seit .NET 8 eingebaut:
var zeit = new FakeTimeProvider(new DateTimeOffset(2026, 7, 1, 0, 0, 0, TimeSpan.Zero));
var pruefung = new Gutscheinpruefung(zeit);
Assert.False(pruefung.IstGueltig(gutschein)); // heute ist immer der 01.07.2026Self-validating — selbstprüfend
Ein Test ist grün oder rot. Er gibt nichts aus, was jemand ansehen müsste:
Braucht einen Menschen
[Fact]
public void BerechneTest()
{
var preis = rabatt.Berechne(100m, 6);
Console.WriteLine(preis);
// und jetzt? Wer schaut hin?
}Prüft selbst
[Fact]
public void Berechne_AbSechsArtikeln_GibtZehnProzent()
{
var preis = rabatt.Berechne(100m, 6);
Assert.Equal(90m, preis);
}Ein Test ohne Assert ist kein Test — er ist ein Programm, das nicht abgestürzt ist.
Timely — rechtzeitig
Geschrieben, solange die Anforderung noch klar ist — bei testgetriebener Entwicklung vor dem Code, sonst unmittelbar danach. Tests, die «wir später nachziehen», werden meistens nicht nachgezogen; und wenn doch, sind sie an der bestehenden Implementierung entlang geschrieben statt an der Anforderung. Sie bestätigen dann, was der Code tut — auch dort, wo er es falsch tut.
Kurz nachgedacht
Zählt nicht — nur zum Prüfen, ob es angekommen ist.
1.Ein Test läuft einzeln grün, in der Suite rot. Welche FIRST-Eigenschaft fehlt?