Testowanie jednostkowe języka C# na platformie .NET przy użyciu testu dotnet i narzędzia xUnit

W tym samouczku pokazano, jak utworzyć rozwiązanie zawierające projekt testu jednostkowego i projekt kodu źródłowego. Aby wykonać czynności opisane w samouczku przy użyciu wstępnie utworzonego rozwiązania, wyświetl lub pobierz przykładowy kod. Aby uzyskać instrukcje dotyczące pobierania, zobacz Przykłady i samouczki.

Tworzenie rozwiązania

W tej sekcji tworzone jest rozwiązanie zawierające projekty źródłowe i testowe. Ukończone rozwiązanie ma następującą strukturę katalogów:

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

Poniższe instrukcje zawierają kroki tworzenia rozwiązania testowego. Zobacz Polecenia służące do tworzenia rozwiązania testowego, aby uzyskać instrukcje dotyczące tworzenia rozwiązania testowego w jednym kroku.

  • Otwórz okno powłoki.

  • Uruchom następujące polecenie:

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

    Polecenie dotnet new sln tworzy nowe rozwiązanie w katalogu unit-testing-using-dotnet-test .

  • Zmień katalog na folder unit-testing-using-dotnet-test .

  • Uruchom następujące polecenie:

    dotnet new classlib -o PrimeService
    

    Polecenie dotnet new classlib tworzy nowy projekt biblioteki klas w folderze PrimeService . Nowa biblioteka klas będzie zawierać kod do przetestowania.

  • Zmień nazwę Class1.cs na PrimeService.cs.

  • Zastąp kod w PrimeService.cs następującym kodem:

    using System;
    
    namespace Prime.Services
    {
        public class PrimeService
        {
            public bool IsPrime(int candidate)
            {
                throw new NotImplementedException("Not implemented.");
            }
        }
    }
    
  • Powyższy kod ma następujące działanie:

    • NotImplementedException Zgłasza komunikat z komunikatem wskazującym, że nie został zaimplementowany.
    • Zostanie zaktualizowany w dalszej części tego samouczka.
  • W katalogu unit-testing-using-dotnet-test uruchom następujące polecenie, aby dodać projekt biblioteki klas do rozwiązania:

    dotnet sln add ./PrimeService/PrimeService.csproj
    
  • Utwórz projekt PrimeService.Tests, uruchamiając następujące polecenie:

    dotnet new xunit -o PrimeService.Tests
    
  • Poprzednie polecenie:

    • Tworzy projekt PrimeService.Tests w katalogu PrimeService.Tests. Projekt testowy używa narzędzia xUnit jako biblioteki testowej.
    • Konfiguruje moduł uruchamiający testy przez dodanie następujących <PackageReference />elementów do pliku projektu:
      • Microsoft.NET.Test.Sdk
      • xunit
      • xunit.runner.visualstudio
      • coverlet.collector
  • Dodaj projekt testowy do pliku rozwiązania, uruchamiając następujące polecenie:

    dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
    
  • Dodaj bibliotekę PrimeService klas jako zależność do projektu PrimeService.Tests :

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

Polecenia umożliwiające utworzenie rozwiązania

Ta sekcja zawiera podsumowanie wszystkich poleceń w poprzedniej sekcji. Pomiń tę sekcję, jeśli wykonano kroki opisane w poprzedniej sekcji.

Następujące polecenia umożliwiają utworzenie rozwiązania testowego na maszynie z systemem Windows. W przypadku systemów macOS i Unix zaktualizuj ren polecenie do wersji ren systemu operacyjnego, aby zmienić nazwę pliku:

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

Postępuj zgodnie z instrukcjami dotyczącymi funkcji "Zastąp kod w PrimeService.cs następującym kodem" w poprzedniej sekcji.

Tworzenie testu

Popularnym podejściem w procesie programowania opartego na testach (TDD) jest napisanie (niepowodzenie) testu przed zaimplementowaniem kodu docelowego. W tym samouczku jest używane podejście TDD. Metoda IsPrime jest wywoływana, ale nie zaimplementowana. Wywołanie testowe kończy się niepowodzeniem IsPrime . W przypadku TDD test jest napisany, który jest znany jako niepowodzenie. Kod docelowy jest aktualizowany w celu wykonania testu. Powtarzasz to podejście, pisząc test kończący się niepowodzeniem, a następnie aktualizując kod docelowy do przekazania.

Zaktualizuj projekt PrimeService.Tests:

  • Usuń plik PrimeService.Tests/UnitTest1.cs.
  • Utwórz plik PrimeService.Tests/PrimeService_IsPrimeShould.cs.
  • Zastąp kod w PrimeService_IsPrimeShould.cs następującym kodem:
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");
        }
    }
}

Atrybut [Fact] deklaruje metodę testową uruchamianą przez moduł uruchamiający testy. W folderze PrimeService.Tests uruchom polecenie dotnet test. Polecenie dotnet test kompiluje zarówno projekty, jak i uruchamia testy. Moduł uruchamiający testy xUnit zawiera punkt wejścia programu w celu uruchomienia testów. dotnet test uruchamia moduł uruchamiający testy przy użyciu projektu testów jednostkowych.

Test kończy się niepowodzeniem, ponieważ IsPrime nie został zaimplementowany. Korzystając z podejścia TDD, napisz tylko wystarczająco dużo kodu, aby ten test przebiegł pomyślnie. Zaktualizuj IsPrime za pomocą następującego kodu:

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

Uruchom program dotnet test. Test zakończy się pomyślnie.

Dodawanie kolejnych testów

Dodaj testy liczb pierwszych dla 0 i -1. Możesz skopiować test utworzony w poprzednim kroku i utworzyć kopie następującego kodu w celu przetestowania wartości 0 i -1. Ale nie rób tego, ponieważ jest lepszy sposób.

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

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

Kopiowanie kodu testowego, gdy tylko parametr zmienia się, powoduje duplikowanie kodu i przeloowanie testowe. Następujące atrybuty xUnit umożliwiają pisanie zestawu podobnych testów:

  • [Theory] reprezentuje zestaw testów, które wykonują ten sam kod, ale mają różne argumenty wejściowe.
  • [InlineData] atrybut określa wartości dla tych danych wejściowych.

Zamiast tworzyć nowe testy, zastosuj poprzednie atrybuty xUnit, aby utworzyć jedną teorię. Zastąp następujący kod:

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

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

z następującym kodem:

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

W poprzednim kodzie [Theory] i [InlineData] włącz testowanie kilku wartości mniejszych niż dwa. Dwa to najmniejsza liczba główna.

Dodaj następujący kod po deklaracji klasy i przed atrybutem [Theory] :

private readonly PrimeService _primeService;

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

Uruchom polecenie dotnet test, a dwa testy kończą się niepowodzeniem. Aby wszystkie testy przeszły, zaktualizuj metodę IsPrime przy użyciu następującego kodu:

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

Zgodnie z podejściem TDD dodaj więcej testów zakończonych niepowodzeniem, a następnie zaktualizuj kod docelowy. Zobacz ukończoną wersję testów i pełną implementację biblioteki.

Ukończona IsPrime metoda nie jest wydajnym algorytmem testowania pierwotnego.

Dodatkowe zasoby