Wird geladen...

Schreiben von Unit-Tests in C# (xUnit, NUnit, MSTest)

Lernen Sie Unit-Tests in C# mit xUnit, NUnit und MSTest zu schreiben, um zuverlässige Software zu entwickeln.

In der Softwareentwicklung stellen Unit-Tests (Komponententests) sicher, dass die kleinsten Teile einer Anwendung (Methoden, Klassen oder Funktionen) isoliert korrekt funktionieren. In C# sind die am häufigsten verwendeten Testframeworks xUnit, NUnit und MSTest. Unit-Tests helfen dabei, Fehler frühzeitig zu erkennen, die Codequalität zu verbessern und sicheres Refactoring zu ermöglichen.


Was ist ein Unit-Test?

Unit-Tests prüfen, ob eine Methode für gegebene Eingaben die erwarteten Ausgaben liefert. Die Tests werden in der Regel für jedes Szenario isoliert und ohne externe Abhängigkeiten (Datenbanken, Dateisysteme, Netzwerke) ausgeführt.


// Beispiel: Zu testende Methode
public class Rechner
{
    public int Addiere(int a, int b) => a + b;
}

Im obigen Beispiel ist die Methode Addiere die zu testende Einheit.


Ein Testprojekt erstellen

Ein Testprojekt kann einfach über Visual Studio oder die .NET-CLI erstellt werden:


// Testprojekt mit xUnit erstellen
dotnet new xunit -n Rechner.Tests
cd Rechner.Tests

// Hauptprojekt als Referenz hinzufügen
dotnet add reference ../Rechner/Rechner.csproj

Alternativ können Sie auch die Vorlagen nunit oder mstest verwenden:


dotnet new nunit -n ProjektName.Tests
dotnet new mstest -n ProjektName.Tests

Tests mit xUnit schreiben

xUnit ist ein modernes und flexibles Testframework und gehört zu den beliebtesten in der C#-Welt. Das Attribut [Fact] kennzeichnet einzelne Tests, während [Theory] für parametrisierte Tests verwendet wird.


using Xunit;

public class RechnerTests
{
    [Fact]
    public void Addiere_SollKorrektesErgebnisLiefern()
    {
        // Arrange
        var r = new Rechner();

        // Act
        int ergebnis = r.Addiere(2, 3);

        // Assert
        Assert.Equal(5, ergebnis);
    }

    [Theory]
    [InlineData(1, 2, 3)]
    [InlineData(-1, 5, 4)]
    [InlineData(10, -2, 8)]
    public void Addiere_SollMitVerschiedenenWertenFunktionieren(int a, int b, int erwartet)
    {
        var r = new Rechner();
        Assert.Equal(erwartet, r.Addiere(a, b));
    }
}

Fact: Testet ein einzelnes Szenario. Theory: Testet dieselbe Methode mit mehreren Datensätzen.


Tests mit NUnit schreiben

NUnit ist ein leistungsstarkes und etabliertes Testframework in der C#-Welt. Es ist bekannt für seine Einfachheit und die große Auswahl an Assertions.


using NUnit.Framework;

[TestFixture]
public class RechnerTests
{
    private Rechner rechner;

    [SetUp]
    public void Setup()
    {
        rechner = new Rechner();
    }

    [Test]
    public void Addiere_Test()
    {
        int ergebnis = rechner.Addiere(4, 6);
        Assert.That(ergebnis, Is.EqualTo(10));
    }

    [TestCase(1, 2, 3)]
    [TestCase(5, 5, 10)]
    public void Addiere_MitVerschiedenenWerten_Test(int a, int b, int erwartet)
    {
        Assert.That(rechner.Addiere(a, b), Is.EqualTo(erwartet));
    }
}

In NUnit wird die [SetUp]-Methode vor jedem Test ausgeführt, und [TestCase] wird für parametrisierte Tests verwendet.


Tests mit MSTest schreiben

MSTest ist das in Visual Studio integrierte Testframework von Microsoft. Es wird besonders in großen Unternehmensprojekten häufig verwendet.


using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class RechnerTests
{
    private Rechner rechner;

    [TestInitialize]
    public void Init()
    {
        rechner = new Rechner();
    }

    [TestMethod]
    public void Addiere_Test()
    {
        int ergebnis = rechner.Addiere(2, 8);
        Assert.AreEqual(10, ergebnis);
    }

    [DataTestMethod]
    [DataRow(1, 1, 2)]
    [DataRow(-3, 5, 2)]
    public void Addiere_MitVerschiedenenWerten_Test(int a, int b, int erwartet)
    {
        Assert.AreEqual(erwartet, rechner.Addiere(a, b));
    }
}

In MSTest sorgt [TestInitialize] für die Initialisierung vor jedem Test, während [DataTestMethod] für datengesteuerte Tests verwendet wird.


Assert-Methoden (Überprüfungsmethoden)

Alle Testframeworks enthalten ähnliche Überprüfungsstrukturen (Assertions):


// Beispiel: Ausnahme-Test
[Fact]
public void Teilen_SollteDivideByZeroExceptionWerfen()
{
    var rechner = new Rechner();
    Assert.Throws<DivideByZeroException>(() => rechner.Teilen(5, 0));
}

Tests Ausführen

Tests können über die CLI oder in Visual Studio ausgeführt werden:


// Tests mit der .NET CLI ausführen
dotnet test

In Visual Studio können Tests über das Fenster “Test Explorer” ausgeführt werden, wobei erfolgreiche und fehlgeschlagene Tests grafisch angezeigt werden.


Mocking und Isolierung von Abhängigkeiten

Mocking wird verwendet, um reale Abhängigkeiten von der Testumgebung zu trennen. Dadurch werden Tests nur auf die Zielmethode fokussiert und nicht von externen Faktoren (z. B. Datenbanken oder Diensten) beeinflusst.


using Moq;
using Xunit;

public interface IEmailDienst
{
    void Senden(string adresse, string nachricht);
}

public class BenutzerRegistrierung
{
    private readonly IEmailDienst _mail;
    public BenutzerRegistrierung(IEmailDienst mail) => _mail = mail;

    public void Registrieren(string name)
    {
        _mail.Senden("admin@site.com", $"{name} wurde registriert.");
    }
}

public class BenutzerRegistrierungTests
{
    [Fact]
    public void Registrieren_SollteEmailSenden()
    {
        var mock = new Mock<IEmailDienst>();
        var registrierung = new BenutzerRegistrierung(mock.Object);

        registrierung.Registrieren("Hans");

        mock.Verify(m => m.Senden("admin@site.com", "Hans wurde registriert."), Times.Once);
    }
}

Die Bibliothek Moq erstellt Mock-Objekte, um die Testumgebung zu isolieren.


Testorganisation und Benennung


Praxisbeispiel: Test der Bestellsumme

Das folgende Beispiel testet die Berechnung der Gesamtsumme einer Bestellung.


// Anwendungscode
public class Bestellung
{
    public List<decimal> ProduktPreise { get; set; } = new();
    public decimal Gesamt() => ProduktPreise.Sum();
}

// Test
public class BestellungTests
{
    [Fact]
    public void Gesamt_SollteKorrektesErgebnisLiefern()
    {
        var b = new Bestellung();
        b.ProduktPreise.AddRange(new[] { 10m, 20m, 30m });
        Assert.Equal(60m, b.Gesamt());
    }
}

Dieses Beispiel ist ein einfacher Unit-Test, der sicherstellt, dass die Geschäftslogik korrekt funktioniert.


Performance und Best Practices


TL;DR

  • Unit Test: Testet kleine, isolierte Codeeinheiten.
  • xUnit: Modern, minimalistisch und weit verbreitet in der .NET-Community.
  • NUnit: Klassisches Framework mit starken Assertions und Attribut-basiertem Ansatz.
  • MSTest: Microsofts integrierte Lösung, vollständig in Visual Studio eingebunden.
  • Mocking: Isoliert externe Abhängigkeiten mit Fake-Objekten.
  • AAA-Modell: Folgen Sie dem Arrange–Act–Assert-Muster.
  • Mit dem Befehl dotnet test lassen sich alle Tests über die CLI ausführen.

Ähnliche Artikel