Komponententests für C# in .NET mit „dotnet test“ und „xUnit“

In diesem Tutorial wird gezeigt, wie Sie eine Lösung erstellen, die ein Komponententest- und ein Quellcodeprojekt enthält. Um dem Tutorial mit einer vorkonfigurierten Projektmappe zu folgen, können Sie sich den Beispielcode ansehen oder ihn herunterladen. Anweisungen zum Herunterladen finden Sie unter Beispiele und Lernprogramme.

Erstellen der Projektmappe

In diesem Abschnitt wird eine Projektmappe erstellt, die das Quell- und Testprojekt enthält. Die vervollständigte Projektmappe hat die folgende Verzeichnisstruktur:

/unit-testing-using-dotnet-test
    unit-testing-using-dotnet-test.sln
    /PrimeService
        PrimeService.cs
        PrimeService.csproj
    /PrimeService.Tests
        PrimeService_IsPrimeShould.cs
        PrimeServiceTests.csproj

In den folgenden Anweisungen werden die Schritte zur Erstellung der Testprojektmappe beschrieben. Anweisungen zum Erstellen der Testprojektmappe in einem Schritt finden Sie unter Befehle zum Erstellen einer Testprojektmappe.

  • Öffnen eines Shell-Fensters.

  • Führen Sie den folgenden Befehl aus:

    dotnet new sln -o unit-testing-using-dotnet-test
    

    Der Befehl dotnet new sln erstellt im Verzeichnis unit-testing-using-dotnet-test eine neue Projektmappe.

  • Ändern Sie das Verzeichnis in unit-testing-using-dotnet-test.

  • Führen Sie den folgenden Befehl aus:

    dotnet new classlib -o PrimeService
    

    Der Befehl dotnet new classlib erstellt ein neues Klassenbibliotheksprojekt im Ordner PrimeService. Die neue Klassenbibliothek enthält den zu testenden Code.

  • Benennen Sie Class1.cs in PrimeService.cs um.

  • Ersetzen Sie den Code in PrimeService.cs durch folgenden Code:

    using System;
    
    namespace Prime.Services
    {
        public class PrimeService
        {
            public bool IsPrime(int candidate)
            {
                throw new NotImplementedException("Not implemented.");
            }
        }
    }
    
  • Der vorangehende Code:

    • Löst eine NotImplementedException mit der Meldung aus, dass die Implementierung fehlt.
    • Wird später im Tutorial aktualisiert.
  • Führen Sie im Verzeichnis unit-testing-using-dotnet-test den folgenden Befehl aus, um das Klassenbibliotheksprojekt zur Projektmappe hinzuzufügen:

    dotnet sln add ./PrimeService/PrimeService.csproj
    
  • Erstellen Sie das Projekt PrimeService.Tests, indem Sie den folgenden Befehl ausführen:

    dotnet new xunit -o PrimeService.Tests
    
  • Für den obigen Befehl gilt Folgendes:

    • Erstellt das Projekt PrimeService.Tests im Verzeichnis PrimeService.Tests. Das Testprojekt verwendet xUnit als Testbibliothek.
    • Konfiguriert den Test Runner, indem die folgenden <PackageReference />-Elemente zur Projektdatei hinzugefügt werden:
      • Microsoft.NET.Test.Sdk
      • xunit
      • xunit.runner.visualstudio
      • coverlet.collector
  • Fügen Sie das Testprojekt zur Projektmappendatei hinzu, indem Sie den folgenden Befehl ausführen:

    dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
    
  • Fügen Sie die Klassenbibliothek PrimeService dem Projekt PrimeService.Tests als Abhängigkeit hinzu:

    dotnet add ./PrimeService.Tests/PrimeService.Tests.csproj reference ./PrimeService/PrimeService.csproj  
    

Befehle zum Erstellen der Projektmappe

In diesem Abschnitt sind alle Befehle des vorherigen Abschnitts zusammengefasst. Überspringen Sie diesen Abschnitt, wenn Sie die Schritte im vorherigen Abschnitt ausgeführt haben.

Die folgenden Befehle erstellen die Testprojektmappe auf einem Windows-Computer. Ändern Sie unter macOS und UNIX den Befehl ren in die Betriebssystemversion von ren, um eine Datei umzubenennen:

dotnet new sln -o unit-testing-using-dotnet-test
cd unit-testing-using-dotnet-test
dotnet new classlib -o PrimeService
ren .\PrimeService\Class1.cs PrimeService.cs
dotnet sln add ./PrimeService/PrimeService.csproj
dotnet new xunit -o PrimeService.Tests
dotnet add ./PrimeService.Tests/PrimeService.Tests.csproj reference ./PrimeService/PrimeService.csproj
dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj

Befolgen Sie die Anweisungen unter „Ersetzen Sie den Code in PrimeService.cs durch folgenden Code“ im vorherigen Abschnitt.

Erstellen eines Tests

Ein beliebter Ansatz bei der testgesteuerten Entwicklung ist das Schreiben eines (fehlerhaften) Tests vor Implementierung des Zielcodes. In diesem Tutorial wird der Ansatz der testgesteuerten Entwicklung befolgt. Die IsPrime-Methode ist aufrufbar, aber nicht implementiert. Ein Testaufruf von IsPrime schlägt fehl. Bei der testgesteuerten Entwicklung wird ein Test geschrieben, der bekanntermaßen fehlschlägt. Der Zielcode wird aktualisiert, damit der Test bestanden wird. Sie wiederholen diesen Ansatz kontinuierlich, schreiben einen nicht erfolgreichen Test und aktualisieren dann den Zielcode so, dass er bestanden wird.

Aktualisieren Sie das Projekt PrimeService.Tests:

  • Löschen Sie PrimeService.Tests/UnitTest1.cs.
  • Erstellen Sie die Datei PrimeService.Tests/PrimeService_IsPrimeShould.cs.
  • Ersetzen Sie den Code in PrimeService_IsPrimeShould.cs durch folgenden Code:
using Xunit;
using Prime.Services;

namespace Prime.UnitTests.Services
{
    public class PrimeService_IsPrimeShould
    {
        [Fact]
        public void IsPrime_InputIs1_ReturnFalse()
        {
            var primeService = new PrimeService();
            bool result = primeService.IsPrime(1);

            Assert.False(result, "1 should not be prime");
        }
    }
}

Das [Fact]-Attribut deklariert eine Testmethode, die vom Test Runner ausgeführt wird. Führen Sie dotnet test im Ordner PrimeService.Tests aus. Der Befehl dotnet test erstellt beide Projekte und führt die Tests aus. Der Test Runner für xUnit enthält den Programmeinstiegspunkt zum Ausführen der Tests. dotnet test startet den Test Runner mithilfe des Komponententestprojekts.

Der Test schlägt fehl, da IsPrime nicht implementiert wurde. Schreiben Sie bei Befolgen des Ansatzes zur testgesteuerten Entwicklung nur so viel Code, dass dieser Test bestanden wird. Aktualisieren Sie IsPrime mit folgendem Code:

public bool IsPrime(int candidate)
{
    if (candidate == 1)
    {
        return false;
    }
    throw new NotImplementedException("Not fully implemented.");
}

Führen Sie aus dotnet test. Der Test wurde erfolgreich ausgeführt.

Hinzufügen weiterer Tests

Fügen Sie Primzahlentests für 0 und-1 hinzu. Sie könnten den im vorherigen Schritt erstellten Test kopieren und Kopien des folgenden Codes erstellen, um 0 und -1 zu testen. Aber tun Sie es nicht, es gibt eine bessere Möglichkeit.

var primeService = new PrimeService();
bool result = primeService.IsPrime(1);

Assert.False(result, "1 should not be prime");

Das Kopieren von Testcode, wenn sich nur ein Parameter ändert, führt zu Codeduplizierung und Testüberfrachtung. Die folgenden xUnit-Attribute ermöglichen das Schreiben einer Sammlung ähnlicher Tests:

  • [Theory] repräsentiert eine Reihe von Tests, die zwar denselben Code ausführen, aber unterschiedliche Eingabeargumente verwenden.
  • Das [InlineData]-Attribut gibt Werte für diese Eingaben an.

Anstatt neue Tests zu erstellen, wenden Sie die vorhergehenden xUnit-Attribute an, um eine einzelne Theorie zu erstellen. Ersetzen Sie den folgenden Code:

[Fact]
public void IsPrime_InputIs1_ReturnFalse()
{
    var primeService = new PrimeService();
    bool result = primeService.IsPrime(1);

    Assert.False(result, "1 should not be prime");
}

durch den folgenden Code:

[Theory]
[InlineData(-1)]
[InlineData(0)]
[InlineData(1)]
public void IsPrime_ValuesLessThan2_ReturnFalse(int value)
{
    var result = _primeService.IsPrime(value);

    Assert.False(result, $"{value} should not be prime");
}

Im vorangehenden Code ermöglichen [Theory] und [InlineData] das Testen mehrerer Werte, die kleiner als 2 sind. 2 ist die kleinste Primzahl.

Fügen Sie den folgenden Code nach der Klassendeklaration und vor dem [Theory]-Attribut hinzu:

private readonly PrimeService _primeService;

public PrimeService_IsPrimeShould()
{
    _primeService = new PrimeService();
}

Führen Sie dotnet test aus, und zwei dieser Tests sind nicht erfolgreich. Aktualisieren Sie die IsPrime-Methode mit folgendem Code, damit alle Tests bestanden werden:

public bool IsPrime(int candidate)
{
    if (candidate < 2)
    {
        return false;
    }
    throw new NotImplementedException("Not fully implemented.");
}

Fügen Sie unter Befolgen des Ansatzes zur testgesteuerten Entwicklung weitere nicht erfolgreiche Tests hinzu, und aktualisieren Sie anschließend den Zielcode. Sehen Sie sich die endgültige Version der Tests und die vollständige Implementierung der Bibliothek an.

Die vervollständigte IsPrime-Methode ist kein effizienter Algorithmus für den Primzahltest.

Zusätzliche Ressourcen