Exercício – Corrigir uma falha de teste

Concluído

Neste ponto, você tem uma maneira de executar testes de unidade à medida que as alterações avançam pelo pipeline de build. Você também tem uma maneira de medir a quantidade de código que é coberta pelos seus testes.

É sempre uma boa ideia executar seus testes localmente antes de enviar as alterações ao pipeline. No entanto, o que acontece quando alguém esquece e envia uma alteração que interrompe o build?

Nesta unidade, você corrigirá um build quebrado causado por um teste de unidade com falha. Aqui, você vai:

  • Obtenha o código inicial do GitHub.
  • Adicione ferramentas de cobertura de código ao seu projeto.
  • Enviar o código por push para o seu repositório.
  • Assistir ao pipeline ser executado automaticamente e os testes de unidade falharem.
  • Reproduzir a falha localmente.
  • Analisar e corrigir a falha.
  • Enviar uma correção por push e assistir à compilação ser bem-sucedida.

Examinar o novo teste de unidade

O recurso mais recente da equipe envolve o placar de líderes. Precisamos obter o número de pontuações do banco de dados, para que possamos gravar um teste de unidade para verificar o método IDocumentDBRepository<T>.GetItemsAsync.

O teste é como mostrado a seguir. Não é necessário adicionar nenhum código ainda.

[TestCase(0, ExpectedResult=0)]
[TestCase(1, ExpectedResult=1)]
[TestCase(10, ExpectedResult=10)]
public int ReturnRequestedCount(int count)
{
    const int PAGE = 0; // take the first page of results

    // Fetch the scores.
    Task<IEnumerable<Score>> scoresTask = _scoreRepository.GetItemsAsync(
        score => true, // return all scores
        score => 1, // we don't care about the order
        PAGE,
        count // fetch this number of results
    );
    IEnumerable<Score> scores = scoresTask.Result;

    // Verify that we received the specified number of items.
    return scores.Count();
}

Lembre-se de que, em um teste NUnit, TestCase fornece dados embutidos para usar esse método de teste. A NUnit chama o método de teste de unidade ReturnRequestedCount como este:

ReturnRequestedCount(0);
ReturnRequestedCount(1);
ReturnRequestedCount(10);

Este teste também usa a propriedade ExpectedResult para simplificar o código de teste e ajudar a esclarecer sua intenção. A NUnit compara automaticamente o valor retornado com relação ao valor dessa propriedade, eliminando a necessidade de chamar explicitamente a asserção.

Escolheremos alguns valores que representam consultas típicas. Também incluiremos 0 para cobrir esse caso de borda.

Buscar o branch do GitHub

Como você fez anteriormente, busque o branch failed-test do GitHub e faça check-out (ou alterne para) esse branch.

  1. No Visual Studio Code, abra o terminal integrado.

  2. Execute os seguintes comandos git fetch e git checkout para baixar um branch chamado failed-test do repositório da Microsoft e mudar para esse branch:

    git fetch upstream failed-test
    git checkout -B failed-test upstream/failed-test
    

    Demos ao branch o nome failed-test para fins de aprendizado. Na prática, você nomearia um branch após sua finalidade ou recurso.

  3. Execute estes comandos para criar um arquivo de manifesto da ferramenta local, instale a ferramenta ReportGenerator e adicione o pacote coverlet.msbuild ao seu projeto de testes:

    dotnet new tool-manifest
    dotnet tool install dotnet-reportgenerator-globaltool
    dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
    

    Esta etapa é necessária porque a ramificação failed-test não contém o trabalho que você adicionou à ramificação unit-tests.

  4. Adicione o arquivo de projeto de teste e o arquivo de manifesto da ferramenta ao índice de preparo e faça commit das alterações.

    git add Tailspin.SpaceGame.Web.Tests/Tailspin.SpaceGame.Web.Tests.csproj
    git add .config/dotnet-tools.json
    git commit -m "Configure code coverage tests"
    
  5. Execute o seguinte comando git push para fazer upload do branch failed-test para seu repositório GitHub:

    git push origin failed-test
    

Veja a falha de teste do pipeline

Digamos que você estava com pressa e pressionou seu trabalho sem executar os testes uma última vez. Felizmente, o pipeline pode ajudar a capturar problemas no início quando há testes de unidade. Você pode ver isso aqui.

  1. No Azure Pipelines, rastreie o build conforme ele é executado pelo pipeline.

  2. Expanda a tarefa Executar testes de unidade – Versão enquanto ela é executada.

    Você verá que o método de teste ReturnRequestedCount falha.

    Uma captura de tela do painel Azure Pipelines mostrando o log de saída de uma falha de asserção no teste de unidade, esperando 10, mas foi 9.

    O teste é aprovado quando o valor de entrada é 0, mas é reprovado quando o valor de entrada é 1 ou 10.

    O build é publicado para o pipeline somente quando a tarefa anterior é bem-sucedida. Aqui, o build não foi publicado porque os testes de unidade falharam. Isso impede que outras pessoas acidentalmente obtenham um build danificado.

Na prática, você nem sempre vai rastrear manualmente o build enquanto ele é executado. Veja algumas maneiras de descobrir a falha:

  • Uma notificação por email do Azure DevOps

    Você pode configurar o Azure DevOps para enviar uma notificação por email quando o build for concluído. A linha do assunto começa com "[Falha no build]" quando o build falha.

    Uma captura de tela de uma parte de uma notificação por email de falha do build.

  • Azure Test Plans

    No Azure DevOps, selecione Test Plans e Runs. Você verá as execuções de testes recentes, incluindo aquelas que acabaram de ser executadas. Selecione o teste completo mais recente. Você vê que dois dos oito testes falharam.

    Uma captura de tela do resultado da execução de teste do Azure DevOps mostrando que dois dos oito testes falharam como um gráfico de anéis.

  • O painel

    No Azure DevOps, selecione Overview e Dashboards. Você verá que a falha aparece no widget Tendência dos Resultados de Teste. O widget de Cobertura de Código está em branco, o que indica que a cobertura não foi executada.

    Uma captura de tela do widget do gráfico de tendências do painel do Azure DevOps mostrando dois testes reprovados na última execução de teste.

  • A notificação de build

    Embora o branch failed-test não inclua a notificação de build no arquivo README.md, isto é o que você veria no GitHub em caso de falha do build:

    Uma captura de tela da notificação de build do Azure Pipelines no GitHub indicando uma falha.

Analisar a falha de teste

Quando os testes de unidade são reprovados, você normalmente tem duas opções, dependendo da natureza da falha:

  • Se o teste revelar um defeito no código, corrija o código e execute os testes novamente.
  • Se a funcionalidade mudar, ajuste o teste de acordo com os novos requisitos.

Reproduzir a falha localmente

Nesta seção, você reproduzirá a falha localmente.

  1. No Visual Studio Code, abra o terminal integrado.

  2. No terminal, execute este comando dotnet build para compilar o aplicativo:

    dotnet build --configuration Release
    
  3. No terminal, execute este comando dotnet test para executar os testes de unidade:

    dotnet test --no-build --configuration Release
    

    Você deverá ver os mesmos erros que viu no pipeline. Aqui está a parte da saída:

    Starting test execution, please wait...
    A total of 1 test files matched the specified pattern.
      Failed ReturnRequestedCount(1) [33 ms]
      Error Message:
         Expected: 1
      But was:  0
    
      Stack Trace:
         at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context)
       at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0()
       at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action)
    
      Failed ReturnRequestedCount(10) [1 ms]
      Error Message:
         Expected: 10
      But was:  9
    
      Stack Trace:
         at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context)
       at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0()
       at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action)
    
    
    Failed!  - Failed:     2, Passed:     6, Skipped:     0, Total:     8, Duration: 98 ms
    

Encontrar a causa do erro

Você percebe que cada teste com falha produz um resultado com diferença de um. Por exemplo, quando 10 é esperado, o teste retorna 9.

Dê uma olhada no código-fonte do método que está sendo testado, LocalDocumentDBRepository<T>.GetItemsAsync. Você deve ver isto:

public Task<IEnumerable<T>> GetItemsAsync(
    Func<T, bool> queryPredicate,
    Func<T, int> orderDescendingPredicate,
    int page = 1, int pageSize = 10
)
{
    var result = _items
        .Where(queryPredicate) // filter
        .OrderByDescending(orderDescendingPredicate) // sort
        .Skip(page * pageSize) // find page
        .Take(pageSize - 1); // take items

    return Task<IEnumerable<T>>.FromResult(result);
}

Nesse cenário, você pode verificar o GitHub para ver se o arquivo foi alterado recentemente.

Uma captura de tela do GitHub mostrando uma comparação de arquivos em que menos uma operação foi adicionada.

Você suspeita que pageSize - 1 está retornando um resultado a menos e que isso deve ser apenas pageSize. Em nosso cenário, este é um erro que você cometeu ao enviar por push o trabalho sem teste, mas em um cenário real, você pode verificar com o desenvolvedor que alterou o arquivo no GitHub para determinar o motivo da alteração.

Dica

Discussão e colaboração também podem ocorrer no GitHub. Você pode comentar sobre uma solicitação de pull ou abrir um problema.

Corrigir o erro

Nesta seção, você corrigirá o erro alterando o código de volta para seu estado original e executando os testes para verificar a correção.

  1. No Visual Studio Code, abra Tailspin.SpaceGame.Web/LocalDocumentDBRepository.cs no Explorador de Arquivos.

  2. Modifique o método GetItemsAsync, conforme mostrado aqui:

    public Task<IEnumerable<T>> GetItemsAsync(
        Func<T, bool> queryPredicate,
        Func<T, int> orderDescendingPredicate,
        int page = 1, int pageSize = 10
    )
    {
        var result = _items
            .Where(queryPredicate) // filter
            .OrderByDescending(orderDescendingPredicate) // sort
            .Skip(page * pageSize) // find page
            .Take(pageSize); // take items
    
        return Task<IEnumerable<T>>.FromResult(result);
    }
    

    Esta versão muda pageSize - 1 para pageSize.

  3. Salve o arquivo.

  4. No terminal integrado, compile o aplicativo.

    dotnet build --configuration Release
    

    Você deverá ver o build ser executado com sucesso.

    Na prática, você pode executar o aplicativo e testá-lo rapidamente. Para fins de aprendizado, vamos ignorar isso por enquanto.

  5. No terminal, execute os testes de unidade.

    dotnet test --no-build --configuration Release
    

    Você verá que os testes são aprovados.

    Starting test execution, please wait...
    A total of 1 test files matched the specified pattern.
    
    Passed!  - Failed:     0, Passed:     8, Skipped:     0, Total:     8, Duration: 69 ms
    
  6. No terminal integrado, adicione cada arquivo modificado ao índice, faça commit das alterações e efetue push do branch para o GitHub.

    git add .
    git commit -m "Return correct number of items"
    git push origin failed-test
    

    Dica

    O ponto (.) neste exemplo git add é um caractere curinga. Ele corresponde a todos os arquivos não preparados no diretório atual e em todos os subdiretórios.

    Antes de usar esse caractere curinga, é uma boa prática executar git status antes de se comprometer a garantir que você está preparando os arquivos que pretende preparar.

  7. Retornar para o Azure Pipelines. Inspecione a alteração mover-se pelo pipeline. Os testes são aprovados e o build geral é bem-sucedido.

    Opcionalmente, para verificar os resultados dos testes, você pode selecionar as guias Tests e Code Coverage quando o build for concluído.

    Você também pode conferir o painel para ver a tendência de resultados atualizada.

    Uma captura de tela do widget do gráfico de tendência do painel do Azure DevOps mostrando um retorno para todos os testes aprovados.

Ótimo! Você corrigiu o build. Em seguida, você aprenderá a limpar seu ambiente do Azure DevOps.