Eseguire unit test di C# con NUnit e .NET Core

In questa esercitazione viene illustrata un'esperienza interattiva di compilazione passo passo di una soluzione di esempio finalizzata all'apprendimento dei concetti base del testing unità. Se si preferisce seguire l'esercitazione usando una soluzione preesistente, visualizzare o scaricare il codice di esempio prima di iniziare. Per istruzioni sul download, vedere Esempi ed esercitazioni.

Questo articolo è relativo al test di un progetto .NET Core. Se si sta testando un progetto ASP.NET Core, vedere Test di integrazione in ASP.NET Core.

Prerequisiti

  • .NET 8.0 o versioni successive.
  • Un editor di testo o editor di codice di propria scelta.

Creazione del progetto di origine

Aprire una finestra della shell. Creare una directory denominata unit-testing-using-nunit in cui archiviare la soluzione. In questa nuova directory eseguire il comando seguente per creare un nuovo file di soluzione per la libreria di classi e il progetto di test:

dotnet new sln

Creare quindi una directory PrimeService. Finora è stata creata la struttura di directory e file seguente:

/unit-testing-using-nunit
    unit-testing-using-nunit.sln
    /PrimeService

Impostare PrimeService come directory corrente ed eseguire il comando seguente per creare il progetto di origine:

dotnet new classlib

Assegnare il nome PrimeService.cs al file Class1.cs. Si crea un'implementazione non corretta della classe PrimeService:

using System;

namespace Prime.Services
{
    public class PrimeService
    {
        public bool IsPrime(int candidate)
        {
            throw new NotImplementedException("Please create a test first.");
        }
    }
}

Tornare alla directory unit-testing-using-nunit. Eseguire il comando seguente per aggiungere il progetto di libreria di classi alla soluzione:

dotnet sln add PrimeService/PrimeService.csproj

Creazione del progetto di test

Creare quindi la directory PrimeService.Tests. Di seguito è illustrata la struttura di directory:

/unit-testing-using-nunit
    unit-testing-using-nunit.sln
    /PrimeService
        Source Files
        PrimeService.csproj
    /PrimeService.Tests

Impostare PrimeService.Tests come directory corrente e creare un nuovo progetto usando il comando seguente:

dotnet new nunit

Il comando dotnet new crea un progetto di test che usa NUnit come libreria di test. Il modello generato configura il Test Runner nel file PrimeService.Tests.csproj:

<ItemGroup>
  <PackageReference Include="nunit" Version="4.2.2" />
  <PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
  <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
  <PackageReference Include="NUnit.Analyzers" Version="4.3.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
  </PackageReference>
</ItemGroup>

Nota

Prima di .NET 9, il codice generato potrebbe fare riferimento a versioni precedenti del framework di test NUnit. È possibile usare la CLI dotnet per aggiornare i pacchetti. In alternativa, aprire il file PrimeService.Tests.csproj e sostituire i contenuti del gruppo di elementi di riferimento del pacchetto con il codice sopra.

Per creare ed eseguire unit test, il progetto di test richiede altri pacchetti. Il comando dotnet new nel passaggio precedente ha aggiunto Microsoft Test SDK, il framework di test NUnit e l'adattatore di test NUnit. Aggiungere ora la libreria di classi PrimeService come un'altra dipendenza del progetto. Usare il comando dotnet add reference:

dotnet add reference ../PrimeService/PrimeService.csproj

È possibile visualizzare l'intero file nel repository degli esempi su GitHub.

Il layout della soluzione finale è il seguente:

/unit-testing-using-nunit
    unit-testing-using-nunit.sln
    /PrimeService
        Source Files
        PrimeService.csproj
    /PrimeService.Tests
        Test Source Files
        PrimeService.Tests.csproj

Eseguire il comando seguente nella directory unit-testing-using-nunit:

dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj

Creazione del primo test

Si scrive un test con esito negativo, lo si fa passare e quindi si ripete il processo. Nella directory PrimeService.Tests rinominare il file UnitTest1.cs in PrimeService_IsPrimeShould.cs e sostituire l'intero contenuto con il codice seguente:

using NUnit.Framework;
using Prime.Services;

namespace Prime.UnitTests.Services
{
    [TestFixture]
    public class PrimeService_IsPrimeShould
    {
        private PrimeService _primeService;

        [SetUp]
        public void SetUp()
        {
            _primeService = new PrimeService();
        }

        [Test]
        public void IsPrime_InputIs1_ReturnFalse()
        {
            var result = _primeService.IsPrime(1);

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

L'attributo [TestFixture] indica una classe che contiene unit test. L'attributo [Test] indica che il metodo è un metodo di test.

Salvare questo file ed eseguire il comando dotnet test per compilare i test e la libreria di classi ed eseguire i test. Il Test Runner di NUnit include il punto d'ingresso del programma per l'esecuzione dei test. dotnet test avvia il Test Runner usando il progetto di unit test creato.

Il test ha esito negativo. Non è stata ancora creata l'implementazione. Fare in modo che il test sia superato scrivendo il codice più semplice che funzioni nella classe PrimeService:

public bool IsPrime(int candidate)
{
    if (candidate == 1)
    {
        return false;
    }
    throw new NotImplementedException("Please create a test first.");
}

Eseguire di nuovo dotnet test nella directory unit-testing-using-nunit. Il comando dotnet test esegue prima una compilazione del progetto PrimeService e quindi del progetto PrimeService.Tests. Dopo aver compilato entrambi i progetti, viene eseguito questo test. che viene superato.

Aggiunta di altre funzionalità

Ora che il test è stato superato, è necessario scriverne altri. Esistono alcuni altri casi semplici per i numeri primi: 0, -1. È possibile aggiungere nuovi test con l'attributo [Test], ma questa operazione risulta rapidamente noiosa. Sono disponibili altri attributi NUnit che consentono di scrivere una suite di test analoghi. Un attributo [TestCase] viene usato per creare una suite di test che eseguono lo stesso codice, ma hanno argomenti di input diversi. È possibile usare l'attributo [TestCase] per specificare i valori per tali input.

Invece di creare nuovi test, applicare questo attributo per creare un singolo test basato sui dati. Il test basato sui dati è un metodo che verifica vari valori minori di due, ovvero il numero primo più piccolo:

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

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

Eseguire dotnet test. Due test hanno esito negativo. Per assicurare che tutti i test vengano superati, modificare la clausola if all'inizio del metodo Main nel file PrimeService.cs:

if (candidate < 2)

Continuare a eseguire l'iterazione aggiungendo altri test, altre teorie e altro codice nella libreria principale. Si ottiene la versione completa dei test e l'implementazione completa della libreria.

È stata compilata una piccola libreria e un set di unit test per tale libreria. È anche stata strutturata la soluzione in modo che l'aggiunta di nuovi pacchetti e test faccia parte del flusso di lavoro standard. La maggior parte del tempo e dell'impegno è dedicata alla soluzione degli obiettivi dell'applicazione.