Mock-Objekte und Fixtures in C#: Das Geheimnis eines perfekten Unit-Tests

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Warum Ihre Tests lügen – und wie Sie das beheben

\n\n

Stellen Sie sich vor: Sie schreiben perfekten C#-Code, decken ihn mit Tests ab, der grüne Haken leuchtet, die CI-Pipeline ist glücklich. Sie bringen ein Release raus… und die Produktion fällt aus. Kommt Ihnen bekannt vor? Höchstwahrscheinlich liegt das Problem nicht am Code, sondern an den Tests. Sie haben nicht Ihren echten Code getestet, sondern eine „Spielzeug“-Version, die an eine Datenbank, ein Dateisystem oder eine externe API gebunden war.

\n\n

Willkommen in der Welt der Mock-Objekte und Fixtures – zwei Säulen, auf denen hochwertiges Unit-Testing in C# ruht. Ohne sie sind Ihre Tests fragile Integrationstests, die bei der kleinsten Änderung der Umgebung brechen. Mit ihnen erhalten Sie schnelle, isolierte und zuverlässige Tests, die Ihren Code wirklich schützen.

\n\n

In diesem Artikel analysieren wir: Was ist der Unterschied zwischen Mock, Stub und Fake? Wie richtet man Fixtures richtig ein? Und wir zeigen Live-Beispiele mit den beliebten Bibliotheken: Moq, NSubstitute und AutoFixture. Los geht's!

\n\n

Mock, Stub, Fake – worin liegt der Unterschied? (Spoiler: Das ist wichtig)

\n\n

Bevor wir Code schreiben, lassen Sie uns die Begriffe klären. Viele Entwickler verwenden das Wort „Mock“ für alles Mögliche, aber das führt zu Verwirrung. In der Klassifikation von Gerard Meszaros (Buch „xUnit Test Patterns“) gibt es eine klare Trennung:

\n\n
    \n
  • Dummy – ein Objekt, das übergeben, aber nie verwendet wird. Es wird nur zum Füllen von Parametern benötigt.
  • \n
  • Stub – liefert vorbereitete Antworten auf Aufrufe. Sie überprüfen den Zustand (State Verification).
  • \n
  • Fake – eine funktionierende, aber vereinfachte Implementierung (z. B. InMemoryRepository statt einer echten Datenbank).
  • \n
  • Mock – ein Objekt, das das Verhalten überprüft (Behavior Verification). Sie stellen fest, dass eine bestimmte Methode mit bestimmten Argumenten aufgerufen wurde.
  • \n
\n\n

In der Praxis verwenden wir in C# am häufigsten Mock-Objekte (über Moq oder NSubstitute) zur Überprüfung von Interaktionen und Fixtures (über AutoFixture) zur schnellen Generierung von Testdaten. Aber der Reihe nach.

\n\n

Mock-Objekte in C#: Abhängigkeiten isolieren

\n\n

Stellen Sie sich vor, Sie haben einen Service OrderService, der bei einer Bestellung eine E-Mail sendet und Daten in der Datenbank speichert. Ihn „echt“ zu testen bedeutet, jedes Mal E-Mails zu versenden und in die Datenbank zu schreiben. Das ist langsam, unzuverlässig und teuer.

\n\n

Die Lösung ist die Isolation von Abhängigkeiten. Wir ersetzen die realen Objekte (EmailSender, DbContext) durch Mock-Objekte und überprüfen, ob der Service die richtigen Methoden mit den korrekten Parametern aufruft.

\n\n

Beispiel mit Moq (der beliebtesten Bibliothek)

\n\n
public interface IEmailSender\n{\n    void Send(string to, string subject, string body);\n}\n\npublic interface IOrderRepository\n{\n    void Save(Order order);\n}\n\npublic class OrderService\n{\n    private readonly IEmailSender _emailSender;\n    private readonly IOrderRepository _repository;\n\n    public OrderService(IEmailSender emailSender, IOrderRepository repository)\n    {\n        _emailSender = emailSender;\n        _repository = repository;\n    }\n\n    public void PlaceOrder(Order order)\n    {\n        // Geschäftslogik\n        _repository.Save(order);\n        _emailSender.Send(order.CustomerEmail, "Bestellung bestätigt", $"Ihre Bestellung #{order.Id} wurde aufgegeben.");\n    }\n}
\n\n

Jetzt schreiben wir einen Test mit Moq:

\n\n
[TestFixture]\npublic class OrderServiceTests\n{\n    [Test]\n    public void PlaceOrder_ShouldSendEmail_WhenOrderIsValid()\n    {\n        // Arrange\n        var mockEmailSender = new Mock<IEmailSender>();\n        var mockRepository = new Mock<IOrderRepository>();\n        var service = new OrderService(mockEmailSender.Object, mockRepository.Object);\n        var order = new Order { Id =                

Blogs

Buchempfehlungen