Enhetstestning av C# i .NET med dotnet-test och xUnit

Den här självstudien visar hur du skapar en lösning som innehåller ett enhetstestprojekt och ett källkodsprojekt. Om du vill följa självstudien med hjälp av en fördefinierad lösning kan du visa eller ladda ned exempelkoden. Instruktioner för nedladdning finns i Exempel och självstudier.

Skapa lösningen

I det här avsnittet skapas en lösning som innehåller käll- och testprojekten. Den färdiga lösningen har följande katalogstruktur:

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

Följande instruktioner innehåller stegen för att skapa testlösningen. Mer information om hur du skapar testlösningen finns i Kommandon för att skapa testlösningen i ett steg.

  • Öppna ett gränssnittsfönster.

  • Kör följande kommando:

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

    Kommandot dotnet new sln skapar en ny lösning i katalogen unit-testing-using-dotnet-test .

  • Ändra katalogen till mappen unit-testing-using-dotnet-test .

  • Kör följande kommando:

    dotnet new classlib -o PrimeService
    

    Kommandot dotnet new classlib skapar ett nytt klassbiblioteksprojekt i mappen PrimeService . Det nya klassbiblioteket innehåller den kod som ska testas.

  • Byt namn på Class1.cs till PrimeService.cs.

  • Ersätt koden i PrimeService.cs med följande kod:

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

    • Genererar ett NotImplementedException med ett meddelande som anger att det inte har implementerats.
    • Uppdateras senare i självstudien.
  • I katalogen unit-testing-using-dotnet-test kör du följande kommando för att lägga till klassbiblioteksprojektet i lösningen:

    dotnet sln add ./PrimeService/PrimeService.csproj
    
  • Skapa projektet PrimeService.Tests genom att köra följande kommando:

    dotnet new xunit -o PrimeService.Tests
    
  • Kommandot ovan:

    • Skapar projektet PrimeService.Tests i katalogen PrimeService.Tests. Testprojektet använder xUnit som testbibliotek.
    • Konfigurerar testlöparen genom att lägga till följande <PackageReference />element i projektfilen:
      • Microsoft.NET.Test.Sdk
      • xunit
      • xunit.runner.visualstudio
      • coverlet.collector
  • Lägg till testprojektet i lösningsfilen genom att köra följande kommando:

    dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
    
  • PrimeService Lägg till klassbiblioteket som ett beroende till projektet PrimeService.Tests:

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

Kommandon för att skapa lösningen

Det här avsnittet sammanfattar alla kommandon i föregående avsnitt. Hoppa över det här avsnittet om du har slutfört stegen i föregående avsnitt.

Följande kommandon skapar testlösningen på en Windows-dator. För macOS och Unix uppdaterar ren du kommandot till os-versionen av ren för att byta namn på en fil:

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

Följ anvisningarna för "Ersätt koden i PrimeService.cs med följande kod" i föregående avsnitt.

Skapa test

En populär metod i testdriven utveckling (TDD) är att skriva ett (misslyckas) test innan du implementerar målkoden. I den här självstudien används TDD-metoden. Metoden IsPrime är anropsbar men inte implementerad. Ett testanrop till IsPrime misslyckas. Med TDD skrivs ett test som är känt för att misslyckas. Målkoden uppdateras för att göra testet godkänt. Du upprepar den här metoden hela tiden, skriver ett misslyckat test och uppdaterar sedan målkoden som ska godkännas.

Uppdatera projektet PrimeService.Tests:

  • Ta bort PrimeService.Tests/UnitTest1.cs.
  • Skapa en PrimeService.Tests/PrimeService_IsPrimeShould.cs-fil .
  • Ersätt koden i PrimeService_IsPrimeShould.cs med följande kod:
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");
        }
    }
}

Attributet [Fact] deklarerar en testmetod som körs av testlöparen. Från mappen PrimeService.Tests kör du dotnet test. Dotnet-testkommandot skapar båda projekten och kör testerna. xUnit-testlöparen innehåller programmets startpunkt för att köra testerna. dotnet test startar testlöparen med hjälp av enhetstestprojektet.

Testet misslyckas eftersom IsPrime det inte har implementerats. Med hjälp av TDD-metoden skriver du bara tillräckligt med kod så att det här testet godkänns. Uppdatera IsPrime med följande kod:

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

Kör dotnet test. Testet godkänns.

Lägga till fler tester

Lägg till primtalstester för 0 och -1. Du kan kopiera testet som skapades i föregående steg och göra kopior av följande kod för att testa 0 och -1. Men gör det inte, eftersom det finns ett bättre sätt.

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

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

Kopiering av testkod när endast en parameter ändras resulterar i kodduplicering och uppsvälldhet. Följande xUnit-attribut gör det möjligt att skriva en uppsättning liknande tester:

  • [Theory] representerar en uppsättning tester som kör samma kod men som har olika indataargument.
  • [InlineData] attributet anger värden för dessa indata.

I stället för att skapa nya tester använder du de föregående xUnit-attributen för att skapa en enda teori. Ersätt följande kod:

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

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

med följande kod:

[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");
}

I föregående kod [Theory] och [InlineData] aktivera testning av flera värden som är mindre än två. Två är det minsta primtal.

Lägg till följande kod efter klassdeklarationen och före attributet [Theory] :

private readonly PrimeService _primeService;

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

Kör dotnet testoch två av testerna misslyckas. Uppdatera metoden med följande kod för att göra så att alla tester godkänns IsPrime :

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

Efter TDD-metoden lägger du till fler misslyckade tester och uppdaterar sedan målkoden. Se den färdiga versionen av testerna och den fullständiga implementeringen av biblioteket.

Den slutförda IsPrime metoden är inte en effektiv algoritm för att testa primality.

Ytterligare resurser