Teste unitare cu xUnit ([Fact], [Theory]) în C# (.NET)

Ecosistem .NET: DI, EF Core și teste xUnit.net 2 (șablonul dotnet new xunit)

xUnit este un framework de teste pentru .NET: [Fact] marchează un test, [Theory] cu [InlineData] rulează același test pe mai multe date.

Sintaxă C#
[Fact] public void Test() { Assert.Equal(asteptat, actual); }   [Theory] [InlineData(1, 2)] public void Test(int a, int b) { }

Ce face Teste unitare cu xUnit ([Fact], [Theory])

Testele stau într-un proiect separat, creat cu dotnet new xunit, care face referință la proiectul testat. O metodă publică cu atributul [Fact] este un test; dacă se termină fără excepție, testul trece. Verificările se fac cu clasa Assert: Equal, True, Null, Contains, Throws<T>.

[Theory] marchează un test cu parametri, iar fiecare [InlineData(...)] este un set de valori; xUnit raportează fiecare set ca test separat. Pentru date mai complexe există [MemberData].

xUnit creează o instanță nouă a clasei de test pentru fiecare test, așa că pregătirea comună se pune în constructor, iar curățenia în Dispose. dotnet test compilează și rulează toate testele; numele testelor descriu de obicei scenariul și rezultatul așteptat.

Exemple

Exemplul 1: Fact, Theory și testarea unei excepții

dotnet test rulează aici 5 teste: două [Fact] și trei seturi [InlineData]. Toate trec.

// Magazin/Reduceri.cs
public static class Reduceri
{
    public static int PretFinal(int pret, int procent)
    {
        ArgumentOutOfRangeException.ThrowIfNegative(procent);
        return pret - pret * procent / 100;
    }
}

// Magazin.Tests/ReduceriTests.cs
public class ReduceriTests
{
    [Fact]
    public void PretFinal_FaraReducere_PastreazaPretul()
    {
        Assert.Equal(200, Reduceri.PretFinal(200, 0));
    }

    [Theory]
    [InlineData(200, 10, 180)]
    [InlineData(99, 50, 50)]
    [InlineData(1000, 25, 750)]
    public void PretFinal_CuReducere_ScadeProcentul(int pret, int procent, int asteptat)
    {
        Assert.Equal(asteptat, Reduceri.PretFinal(pret, procent));
    }

    [Fact]
    public void PretFinal_ProcentNegativ_AruncaExceptie()
    {
        Assert.Throws<ArgumentOutOfRangeException>(() => Reduceri.PretFinal(100, -5));
    }
}

Exemplul 2: Crearea proiectului și un test care pică

Dacă metoda ar uita să aplice reducerea, testul pentru (200, 10, 180) pică, iar xUnit arată valoarea așteptată și pe cea primită.

dotnet new xunit -n Magazin.Tests
dotnet add Magazin.Tests/Magazin.Tests.csproj reference Magazin/Magazin.csproj
dotnet test

Fragment din ieșirea dotnet test când un test pică

Assert.Equal() Failure: Values differ
Expected: 180
Actual:   200

Greșeli frecvente

  • Inversarea argumentelor: Assert.Equal(asteptat, actual). Invers, mesajul de eroare spune exact pe dos ce s-a întâmplat.
  • Teste care depind unele de altele sau de ordinea rulării (o variabilă statică partajată). Fiecare test trebuie să-și pregătească singur datele.
  • Metodă de test async void: folosește async Task, altfel xUnit nu așteaptă terminarea ei.

Comenzi înrudite

  • Dependency Injection (ServiceCollection): Containerul DI din .NET creează obiectele și le dă dependențele prin constructor; înregistrezi serviciile ca Singleton, Scoped sau Transient.
  • throw și throw expressions: Aruncă o excepție care oprește execuția normală; throw; simplu re-aruncă excepția prinsă, păstrând locul unde a apărut.
  • NuGet: pachete și PackageReference: NuGet este managerul de pachete .NET: adaugi biblioteci cu dotnet package add, iar proiectul le reține ca PackageReference în .csproj.