Exercício – Executar o teste de unidade em uma Função do Azure

Concluído

O teste de unidade é uma parte fundamental da metodologia Agile. O Visual Studio fornece o modelo de projeto de teste. Use esse modelo para criar os testes de unidade para seus aplicativos e aplique a mesma técnica aos testes do Azure Functions.

No cenário de site de relógios de luxo, sua equipe de desenvolvimento tem uma política de alcançar, pelo menos, 80% da cobertura de código no teste de unidade. Você deseja implementar a mesma política para o Azure Functions.

Aqui, você aprende a usar a estrutura de teste xUnit com o Visual Studio para testar o Azure Functions.

Criar um projeto de teste de unidade

A primeira etapa é criar um projeto que contenha os testes de unidade e adicioná-lo à solução que armazena o Aplicativo de funções do Azure. Use as etapas a seguir para criar um projeto de teste de unidade para testar a função WatchInfo.

  1. Na janela Gerenciador de Soluções do Visual Studio clique com o botão direito do mouse na solução WatchPortalFunction, selecione Adicionar e selecione Novo Projeto.

    Captura de tela do Gerenciador de Soluções mostrando o comando Adicionar novo projeto à solução.

  2. Na janela Adicionar um projeto, role para baixo, selecione o modelo do ícone Projeto de teste do xUnitC#+ e selecione Avançar.

    Captura de tela da janela Adicionar Novo Projeto. O modelo de Projeto de Teste xUnit está selecionado.

  3. A janela Configurar seu novo projeto é exibida. No campo Nome do projeto, insira WatchFunctionsTests. Ao lado do campo Local, selecione o ícone procurar e escolha a pasta WatchPortalFunction.

  4. Selecione Avançar. A janela Informações adicionais é exibida.

  5. Em Estrutura de Destino, aceite o valor padrão do .NET 6.0 (suporte de longo prazo).

  6. Selecione Criar.

  7. Quando o projeto é adicionado, clique com o botão direito do mouse no projeto WatchFunctionTests na janela Gerenciador de Soluções e selecione Gerenciar Pacotes NuGet.

  8. Na janela NuGet: WatchFunctionTests, selecione a guia Procurar. Na caixa Pesquisa, digite Microsoft.AspNetCore.Mvc. Selecione o pacote Microsoft.AspNetCore.Mvc e selecione Instalar.

    Captura de tela da janela Gerenciador de Pacotes NuGet. O usuário está instalando o pacote Microsoft.AspNetCore.Mvc.

    Observação

    O projeto de teste criará um ambiente HTTP fictício. As classes necessárias para fazer isso estão no pacote Microsoft.AspNetCore.Mvc.

  9. Aguarde enquanto o pacote é instalado. Se a caixa de mensagem Visualizar Alterações for exibida, selecione OK. Na caixa de mensagem Aceitação da Licença, selecione Aceito.

  10. Depois de adicionar o pacote, na janela Gerenciador de Soluções, no projeto WatchFunctionsTests, clique com o botão direito do mouse no arquivo UnitTest1.cs e selecione Renomear. Altere o nome do arquivo para WatchFunctionUnitTests.cs. Na caixa de mensagem exibida, para renomear todas as referências de UnitTest1 para WatchFunctionUnitTests, selecione Sim.

  11. Na janela Gerenciador de Soluções, no projeto WatchFunctionsTests, clique com o botão direito do mouse em Dependências e selecione Adicionar referência de projeto.

  12. Na janela Gerenciador de Referências, selecione o projeto WatchPortalFunction e selecione OK.

Adicionar testes de unidade à função WatchInfo

Agora você pode adicionar testes de unidade ao projeto de teste. No cenário de relógios de luxo, você desejará garantir que a função WatchInfo sempre retorne uma resposta OK quando um modelo for fornecido na cadeia de consulta de uma solicitação e uma resposta Inválido se a cadeia de consulta estiver vazia ou não contiver o parâmetro model.

Para verificar esse comportamento, adicione um par de testes Fact ao WatchFunctionsTests.

  1. Na janela Gerenciador de Soluções, para exibir a WatchPortalFunction na janela de código, clique duas vezes no arquivo WatchFunctionUnitTests.cs.

  2. Na parte superior do arquivo, adicione as diretivas using a seguir à lista.

    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Http.Internal;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Primitives;
    using Microsoft.Extensions.Logging.Abstractions;
    
  3. Altere o nome do método Test1 para TestWatchFunctionSuccess.

  4. No corpo do método TestWatchFunctionSuccess, adicione o código a seguir. Essa instrução cria um contexto HTTP e uma solicitação HTTP fictícios. A solicitação inclui uma cadeia de consulta que inclui o parâmetro model, definido como abc.

    var queryStringValue = "abc";
    var request = new DefaultHttpRequest(new DefaultHttpContext())
    {
        Query = new QueryCollection
        (
            new System.Collections.Generic.Dictionary<string, StringValues>()
            {
                { "model", queryStringValue }
            }
        )
    };
    
  5. Adicione a instrução a seguir ao método. Essa instrução cria um agente fictício.

    var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
    
  6. Adicione o código a seguir ao método. Essas instruções invocam a função WatchInfo, passando a solicitação e o agente fictícios como parâmetros.

    var response = WatchPortalFunction.WatchInfo.Run(request, logger);
    response.Wait();
    
  7. Adicione o código a seguir ao método. Esse código verifica se a resposta da função está correta. Nesse caso, a função deve retornar uma resposta OK, contendo os dados esperados no corpo.

    // Check that the response is an "OK" response
    Assert.IsAssignableFrom<OkObjectResult>(response.Result);
    
    // Check that the contents of the response are the expected contents
    var result = (OkObjectResult)response.Result;
    dynamic watchinfo = new { Manufacturer = "abc", CaseType = "Solid", Bezel = "Titanium", Dial = "Roman", CaseFinish = "Silver", Jewels = 15 };
    string watchInfo = $"Watch Details: {watchinfo.Manufacturer}, {watchinfo.CaseType}, {watchinfo.Bezel}, {watchinfo.Dial}, {watchinfo.CaseFinish}, {watchinfo.Jewels}";
    Assert.Equal(watchInfo, result.Value);
    

    O método completo deverá ter a aparência a seguir.

    [Fact]
    public void TestWatchFunctionSuccess()
    {
        var queryStringValue = "abc";
        var request = new DefaultHttpRequest(new DefaultHttpContext())
        {
            Query = new QueryCollection
            (
                new System.Collections.Generic.Dictionary<string, StringValues>()
                {
                    { "model", queryStringValue }
                }
            )
        };
    
        var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
    
        var response = WatchPortalFunction.WatchInfo.Run(request, logger);
        response.Wait();
    
        // Check that the response is an "OK" response
        Assert.IsAssignableFrom<OkObjectResult>(response.Result);
    
        // Check that the contents of the response are the expected contents
        var result = (OkObjectResult)response.Result;
        dynamic watchinfo = new { Manufacturer = "abc", CaseType = "Solid", Bezel = "Titanium", Dial = "Roman", CaseFinish = "Silver", Jewels = 15 };
        string watchInfo = $"Watch Details: {watchinfo.Manufacturer}, {watchinfo.CaseType}, {watchinfo.Bezel}, {watchinfo.Dial}, {watchinfo.CaseFinish}, {watchinfo.Jewels}";
        Assert.Equal(watchInfo, result.Value);
    }
    
  8. Adicione mais dois métodos chamados TestWatchFunctionFailureNoQueryString e TestWatchFunctionFailureNoModel. O TestWatchFunctionFailureNoQueryString verifica se a função WatchInfo falha normalmente caso não receba uma cadeia de consulta. O TestWatchFunctionFailureNoModel verifica a mesma falha se a função recebe uma cadeia de consulta que não contém um parâmetro de modelo.

    [Fact]
    public void TestWatchFunctionFailureNoQueryString()
    {
        var request = new DefaultHttpRequest(new DefaultHttpContext());
        var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
    
        var response = WatchPortalFunction.WatchInfo.Run(request, logger);
        response.Wait();
    
        // Check that the response is an "Bad" response
        Assert.IsAssignableFrom<BadRequestObjectResult>(response.Result);
    
        // Check that the contents of the response are the expected contents
        var result = (BadRequestObjectResult)response.Result;
        Assert.Equal("Please provide a watch model in the query string", result.Value);
    }
    
    [Fact]
    public void TestWatchFunctionFailureNoModel()
    {
        var queryStringValue = "abc";
        var request = new DefaultHttpRequest(new DefaultHttpContext())
        {
            Query = new QueryCollection
            (
                new System.Collections.Generic.Dictionary<string, StringValues>()
                {
                    { "not-model", queryStringValue }
                }
            )
        };
    
        var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
    
        var response = WatchPortalFunction.WatchInfo.Run(request, logger);
        response.Wait();
    
        // Check that the response is an "Bad" response
        Assert.IsAssignableFrom<BadRequestObjectResult>(response.Result);
    
        // Check that the contents of the response are the expected contents
        var result = (BadRequestObjectResult)response.Result;
        Assert.Equal("Please provide a watch model in the query string", result.Value);
    }
    

Executar os testes

  1. Na barra de menus superior, em Teste, selecione Executar todos os testes.

    Captura de tela do menu Teste no Visual Studio. O usuário selecionou Executar – >Todos os testes.

  2. Na janela do Gerenciador de Testes todos os três testes deverão ser concluídos com êxito.

    Captura de tela da janela do Team Explorer. Todos os três testes foram executados com êxito.

  3. Na janela do Gerenciador de Soluções, no projeto WatchPortalFunction, para exibir o arquivo no editor de códigos, clique duas vezes em WatchInfo.cs.

  4. Encontre o código a seguir.

    // Retrieve the model id from the query string
    string model = req.Query["model"];
    
  5. Altere a instrução que define a variável model, conforme mostrado a seguir. Essa alteração simula o desenvolvedor cometendo um erro no código.

    string model = req.Query["modelll"];
    
  6. Na barra de menus superior, em Teste, selecione Executar todos os testes. Desta vez, o teste TestWatchFunctionSuccess deverá falhar. Essa falha ocorre porque a função WatchInfo não encontra o parâmetro chamado modelll na cadeia de caracteres de consulta e, portanto, retorna uma resposta Inválida.

    Captura de tela da janela do Team Explorer. Falha no teste TestWatchFunctionSuccess.

Nesta unidade, você aprendeu a criar um projeto de teste de unidade e implementar testes de unidade para uma Função do Azure.