Teste de unidade de bibliotecas F# usando dotnet test e NUnit

Este tutorial apresenta uma experiência interativa de compilação de uma solução de exemplo passo a passo para aprender os conceitos do teste de unidade. Se preferir seguir o tutorial usando uma solução pré-construída, visualize ou baixe o código de amostra antes de começar. Para obter instruções de download, veja Exemplos e tutoriais.

Este artigo é sobre como testar um projeto do .NET Core. Se você estiver testando um projeto ASP.NET Core, confira Testes de integração no ASP.NET Core.

Pré-requisitos

  • SDK do .NET 8 ou versões posteriores.
  • Um editor de texto ou editor de código de sua escolha.

Crie o projeto de origem

Abra uma janela do shell. Crie um diretório chamado unit-testing-with-fsharp para armazenar a solução. Nesse diretório, execute o seguinte comando a fim de criar um novo arquivo de solução para a biblioteca de classes e o projeto de teste:

dotnet new sln

Em seguida, crie um diretório MathService. A seguinte estrutura de tópicos mostra a estrutura de arquivo e o diretório até aqui:

/unit-testing-with-fsharp
    unit-testing-with-fsharp.sln
    /MathService

Torne MathService o diretório atual e execute o seguinte comando para criar o projeto de origem:

dotnet new classlib -lang "F#"

Crie uma implementação com falha do serviço de matemática:

module MyMath =
    let squaresOfOdds xs = raise (System.NotImplementedException("You haven't written a test yet!"))

Altere o diretório de volta para o diretório unit-testing-with-fsharp. Execute o seguinte comando para adicionar o projeto de biblioteca de classes à solução:

dotnet sln add .\MathService\MathService.fsproj

Criar um projeto de teste

Em seguida, crie o diretório MathService.Tests. O seguinte esquema mostra a estrutura do diretório:

/unit-testing-with-fsharp
    unit-testing-with-fsharp.sln
    /MathService
        Source Files
        MathService.fsproj
    /MathService.Tests

Torne o diretório MathService.Tests o diretório atual e crie um novo projeto usando o seguinte comando:

dotnet new nunit -lang "F#"

Esse comando cria um projeto de teste que usa NUnit como estrutura de teste. O modelo gerado configura o executor de teste no MathServiceTests.fsproj:

<ItemGroup>
  <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
  <PackageReference Include="NUnit" Version="4.1.0" />
  <PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>

O projeto de teste requer outros pacotes para criar e executar testes de unidade. O dotnet new na etapa anterior adicionou o NUnit e o adaptador de teste do NUnit. Agora, adicione a biblioteca de classes MathService como outra dependência ao projeto. Use o comando dotnet add reference:

dotnet add reference ../MathService/MathService.fsproj

Você pode ver o arquivo inteiro no repositório de exemplos no GitHub.

Você tem o seguinte layout de solução final:

/unit-testing-with-fsharp
    unit-testing-with-fsharp.sln
    /MathService
        Source Files
        MathService.fsproj
    /MathService.Tests
        Test Source Files
        MathService.Tests.fsproj

Execute o seguinte comando no diretório unit-testing-with-fsharp:

dotnet sln add .\MathService.Tests\MathService.Tests.fsproj

Crie o primeiro teste

Escreva um teste com falha, faça-o ser aprovado e, em seguida, repita o processo. Abra UnitTest1.fs e adicione o seguinte código:

namespace MathService.Tests

open System
open NUnit.Framework
open MathService

[<TestFixture>]
type TestClass () =

    [<Test>]
    member this.TestMethodPassing() =
        Assert.That(true, Is.True)

    [<Test>]
     member this.FailEveryTime() = Assert.That(false, Is.True)

O atributo [<TestFixture>] indica uma classe que contém testes. O atributo [<Test>] indica um método de teste que é executado pelo executor de teste. No diretório unit-testing-with-fsharp, execute dotnet test para criar os testes e a biblioteca de classes e execute os testes. O executor de teste do NUnit contém o ponto de entrada do programa para executar os testes. dotnet test inicia o executor de teste usando o projeto de teste de unidade que você criou.

Esses dois testes mostram testes com aprovação e falha mais básicos. My test é aprovado e Fail every time falha. Agora, crie um teste para o método squaresOfOdds. O método squaresOfOdds retorna uma sequência dos quadrados de todos os valores inteiros ímpares que fazem parte da sequência de entrada. Em vez de tentar gravar todas as funções de uma vez, você pode criar testes iterativamente que validam a funcionalidade. Para fazer com que cada teste passe, você cria a funcionalidade necessária para o método.

O teste mais simples que você pode escrever é chamar squaresOfOdds com todos os números pares, onde o resultado deve ser uma sequência vazia de inteiros. Este é o teste:

[<Test>]
member this.TestEvenSequence() =
    let expected = Seq.empty<int>
    let actual = MyMath.squaresOfOdds [2; 4; 6; 8; 10]
    Assert.That(actual, Is.EqualTo(expected))

Observe que a sequência expected é convertida em uma lista. A estrutura do NUnit depende de muitos tipos padrão de .NET. Essa dependência significa que sua interface pública e os resultados esperados dão suporte a ICollection em vez de IEnumerable.

Ao executar o teste, você verá que ele falha. Isso ocorre porque você ainda não criou a implementação. Faça esse teste passar escrevendo o código mais simples na classe Library.fs em seu projeto MathService que funciona:

let squaresOfOdds xs =
    Seq.empty<int>

No diretório unit-testing-with-fsharp, execute dotnet test novamente. O comando dotnet test executa uma compilação para o projeto MathService e, depois, para o projeto MathService.Tests. Depois de compilar os dois projetos, ele executa os seus testes. Agora, dois testes são aprovados.

Preencha os requisitos

Agora que você fez um teste ser aprovado, é hora de escrever mais. O próximo caso simples funciona com uma sequência cujo único número ímpar é 1. O número 1 é mais fácil, pois o quadrado de 1 é 1. Este é o próximo teste:

[<Test>]
member public this.TestOnesAndEvens() =
    let expected = [1; 1; 1; 1]
    let actual = MyMath.squaresOfOdds [2; 1; 4; 1; 6; 1; 8; 1; 10]
    Assert.That(actual, Is.EqualTo(expected))

A execução de dotnet test falha no novo teste. Você deve atualizar o método squaresOfOdds para lidar com esse novo teste. É preciso remover todos os números pares da sequência para que esse teste seja aprovado. Faça isso escrevendo uma pequena função de filtro e usando Seq.filter:

let private isOdd x = x % 2 <> 0

let squaresOfOdds xs =
    xs
    |> Seq.filter isOdd

Há mais uma etapa a ser executada: eleve ao quadrado cada um dos números ímpares. Comece escrevendo um novo teste:

[<Test>]
member public this.TestSquaresOfOdds() =
    let expected = [1; 9; 25; 49; 81]
    let actual = MyMath.squaresOfOdds [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
    Assert.That(actual, Is.EqualTo(expected))

Você pode corrigir o teste redirecionando a sequência filtrada por meio de uma operação de mapa para calcular o quadrado de cada número ímpar:

let private square x = x * x
let private isOdd x = x % 2 <> 0

let squaresOfOdds xs =
    xs
    |> Seq.filter isOdd
    |> Seq.map square

Você criou uma pequena biblioteca e um conjunto de testes de unidade para essa biblioteca. Você estruturou a solução para que a adição de novos pacotes e testes faça parte do fluxo de trabalho normal. Você concentrou a maior parte do seu tempo e esforço na solução dos objetivos do aplicativo.

Confira também