Compartilhar via


Testes unitários de bibliotecas F# no .NET Core usando dotnet test e xUnit

Este tutorial guia você por uma experiência interativa de construção de uma solução de exemplo passo a passo para aprender conceitos de teste de unidade. Se você preferir acompanhar o tutorial usando uma solução interna, veja ou baixe o exemplo de código antes de começar. Para obter instruções de download, consulte Exemplos e Tutoriais.

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

Criando o projeto de origem

Abra uma janela do shell. Crie um diretório chamado unit-testing-with-fsharp para manter a solução. Dentro desse novo diretório, execute dotnet new sln para criar uma nova solução. Isso facilita o gerenciamento da biblioteca de classes e do projeto de teste de unidade. Dentro do diretório da solução, crie um diretório MathService . O diretório e a estrutura de arquivos até agora são mostrados abaixo:

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

Torne MathService o diretório atual e execute dotnet new classlib -lang "F#" para criar o projeto de origem. Você criará 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 dotnet sln add .\MathService\MathService.fsproj para adicionar o projeto de biblioteca de classes à solução.

Criando o 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 dotnet new xunit -lang "F#". Isso cria um projeto de teste que usa xUnit como a biblioteca de teste. O modelo gerado configura o executor de teste no MathServiceTests.fsproj:

<ItemGroup>
  <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170628-02" />
  <PackageReference Include="xunit" Version="2.2.0" />
  <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
</ItemGroup>

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

dotnet reference add ../MathService/MathService.fsproj

Dica

Se você estiver usando o SDK do .NET 9 ou anterior, use o formulário "verbo primeiro" (dotnet add reference) em vez disso. O formulário "substantivo primeiro" foi introduzido no .NET 10.

Você pode ver todo o arquivo 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
        MathServiceTests.fsproj

Execute dotnet sln add .\MathService.Tests\MathService.Tests.fsproj no diretório unit-testing-with-fsharp.

Criando o primeiro teste

Você escreve um teste com falha, faz com que ele passe e repita o processo. Abra Tests.fs e adicione o seguinte código:

[<Fact>]
let ``My test`` () =
    Assert.True(true)

[<Fact>]
let ``Fail every time`` () = Assert.True(false)

O [<Fact>] atributo indica um método de teste executado pelo executor de teste. No unit-testing-with-fsharp, execute dotnet test para criar os testes e a biblioteca de classes e, em seguida, execute os testes. O executor de teste xUnit contém o ponto de entrada do programa para executar seus 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 passa e Fail every time falha. Agora, crie um teste para o squaresOfOdds método. O squaresOfOdds método 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 essas funções de uma só vez, você pode criar testes iterativamente que validem a funcionalidade. Fazer com que cada teste passe significa criar a funcionalidade necessária para o método.

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

[<Fact>]
let ``Sequence of Evens returns empty collection`` () =
    let expected = Seq.empty<int>
    let actual = MyMath.squaresOfOdds [2; 4; 6; 8; 10]
    Assert.Equal<Collections.Generic.IEnumerable<int>>(expected, actual)

O teste falha. Você ainda não criou a implementação. Faça esse teste passar escrevendo o código mais simples na classe 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 um build para o projeto MathService e, em seguida, para o projeto MathService.Tests. Depois de compilar os dois projetos, ele executará esse teste único. Ele passa.

Como atender aos requisitos

Agora que você fez um teste 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 porque o quadrado de 1 é 1. Este é o próximo teste:

[<Fact>]
let ``Sequences of Ones and Evens returns Ones`` () =
    let expected = [1; 1; 1; 1]
    let actual = MyMath.squaresOfOdds [2; 1; 4; 1; 6; 1; 8; 1; 10]
    Assert.Equal<Collections.Generic.IEnumerable<int>>(expected, actual)

A execução de dotnet test executa os testes e mostra que o novo teste falha. Agora, atualize o squaresOfOdds método para lidar com esse novo teste. Você filtra todos os números pares da sequência para fazer o teste passar. Você pode fazer isso escrevendo uma função de filtro pequena e usando Seq.filter:

let private isOdd x = x % 2 <> 0

let squaresOfOdds xs =
    xs
    |> Seq.filter isOdd

Há mais um passo a percorrer: acertar cada um dos números ímpares. Comece escrevendo um novo teste:

[<Fact>]
let ``SquaresOfOdds works`` () =
    let expected = [1; 9; 25; 49; 81]
    let actual = MyMath.squaresOfOdds [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
    Assert.Equal(expected, actual)

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 unitários 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 resolução das metas do aplicativo.

Consulte também