Estratégias para testar o seu código nas Funções do AzureStrategies for testing your code in Azure Functions

Este artigo demonstra como criar testes automatizados para Funções Azure.This article demonstrates how to create automated tests for Azure Functions.

É recomendável testar todo o código, no entanto poderá obter os melhores resultados, embrulhando a lógica de uma Função e criando testes fora da Função.Testing all code is recommended, however you may get the best results by wrapping up a Function's logic and creating tests outside the Function. A abstração da lógica de distância limita as linhas de código de uma Função e permite que a Função seja a única responsável por chamar outras classes ou módulos.Abstracting logic away limits a Function's lines of code and allows the Function to be solely responsible for calling other classes or modules. Este artigo, no entanto, demonstra como criar testes automatizados contra um HTTP e funções desencadeadas por temporizador.This article, however, demonstrates how to create automated tests against an HTTP and timer-triggered functions.

O conteúdo que se segue é dividido em duas secções diferentes destinadas a direcionar diferentes línguas e ambientes.The content that follows is split into two different sections meant to target different languages and environments. Pode aprender a fazer testes em:You can learn to build tests in:

O repositório de amostras está disponível no GitHub.The sample repository is available on GitHub.

C# no Estúdio VisualC# in Visual Studio

O exemplo a seguir descreve como criar uma aplicação de função C# no Estúdio Visual e executar e testar com xUnit.The following example describes how to create a C# Function app in Visual Studio and run and tests with xUnit.

Testar funções Azure com C# em Estúdio Visual

ConfiguraçãoSetup

Para configurar o seu ambiente, crie uma aplicação de função e teste.To set up your environment, create a Function and test app. Os seguintes passos ajudam-no a criar as aplicações e funções necessárias para suportar os testes:The following steps help you create the apps and functions required to support the tests:

  1. Criar uma nova aplicação funções e nomeá-la FunçõesCreate a new Functions app and name it Functions
  2. Crie uma função HTTP a partir do modelo e nomeie-o MyHttpTrigger.Create an HTTP function from the template and name it MyHttpTrigger.
  3. Crie uma função temporizador a partir do modelo e nomeie-o MyTimerTrigger.Create a timer function from the template and name it MyTimerTrigger.
  4. Crie uma aplicação de teste xUnit na solução e nomeie-a Funções.Testes.Create an xUnit Test app in the solution and name it Functions.Tests.
  5. Utilize o NuGet para adicionar uma referência da aplicação de teste à Microsoft.AspNetCore.MvcUse NuGet to add a reference from the test app to Microsoft.AspNetCore.Mvc
  6. Referenciar a aplicação Funções a partir da aplicação Funções.Testes.Reference the Functions app from Functions.Tests app.

Criar aulas de testeCreate test classes

Agora que os projetos são criados, pode criar as classes usadas para executar os testes automatizados.Now that the projects are created, you can create the classes used to run the automated tests.

Cada função requer um exemplo de ILogger para lidar com o registo de mensagens.Each function takes an instance of ILogger to handle message logging. Alguns testes ou não registam mensagens ou não têm qualquer preocupação com a forma como o registo é implementado.Some tests either don't log messages or have no concern for how logging is implemented. Outros testes precisam de avaliar as mensagens registadas para determinar se um teste está a passar.Other tests need to evaluate messages logged to determine whether a test is passing.

Irá criar uma nova classe com o nome ListLogger de uma lista interna de mensagens para avaliar durante um teste.You'll create a new class named ListLogger which holds an internal list of messages to evaluate during a testing. Para implementar a ILogger interface necessária, a classe precisa de um âmbito.To implement the required ILogger interface, the class needs a scope. A classe seguinte ridiculariza uma margem para que os casos de teste passem para a ListLogger classe.The following class mocks a scope for the test cases to pass to the ListLogger class.

Criar uma nova classe em Funções.Testes projeto nomeado NullScope.cs e introduza o seguinte código:Create a new class in Functions.Tests project named NullScope.cs and enter the following code:

using System;

namespace Functions.Tests
{
    public class NullScope : IDisposable
    {
        public static NullScope Instance { get; } = new NullScope();

        private NullScope() { }

        public void Dispose() { }
    }
}

Em seguida, crie uma nova classe em Funções.Testes projeto nomeado ListLogger.cs e introduza o seguinte código:Next, create a new class in Functions.Tests project named ListLogger.cs and enter the following code:

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;

namespace Functions.Tests
{
    public class ListLogger : ILogger
    {
        public IList<string> Logs;

        public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;

        public bool IsEnabled(LogLevel logLevel) => false;

        public ListLogger()
        {
            this.Logs = new List<string>();
        }

        public void Log<TState>(LogLevel logLevel,
                                EventId eventId,
                                TState state,
                                Exception exception,
                                Func<TState, Exception, string> formatter)
        {
            string message = formatter(state, exception);
            this.Logs.Add(message);
        }
    }
}

A ListLogger classe implementa os seguintes membros conforme contratado pela ILogger interface:The ListLogger class implements the following members as contracted by the ILogger interface:

  • StartScope: Os âmbitos adicionam contexto à sua sessão de registo.BeginScope: Scopes add context to your logging. Neste caso, o teste apenas aponta para a instância estática da NullScope classe para permitir o funcionamento do teste.In this case, the test just points to the static instance on the NullScope class to allow the test to function.

  • IsEnabled: É fornecido um valor false predefinido.IsEnabled: A default value of false is provided.

  • Log: Este método utiliza a função fornecida formatter para formatar a mensagem e, em seguida, adicionar o texto resultante à Logs coleção.Log: This method uses the provided formatter function to format the message and then adds the resulting text to the Logs collection.

A Logs coleção é um exemplo de e é List<string> inicializada no construtor.The Logs collection is an instance of List<string> and is initialized in the constructor.

Em seguida, crie um novo ficheiro em Funções.Testes projeto denominado LoggerTypes.cs e introduza o seguinte código:Next, create a new file in Functions.Tests project named LoggerTypes.cs and enter the following code:

namespace Functions.Tests
{
    public enum LoggerTypes
    {
        Null,
        List
    }
}

Esta enumeração especifica o tipo de madeirão utilizado pelos testes.This enumeration specifies the type of logger used by the tests.

Agora crie uma nova classe em Funções.Testes projeto chamado TestFactory.cs e introduza o seguinte código:Now create a new class in Functions.Tests project named TestFactory.cs and enter the following code:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Primitives;
using System.Collections.Generic;

namespace Functions.Tests
{
    public class TestFactory
    {
        public static IEnumerable<object[]> Data()
        {
            return new List<object[]>
            {
                new object[] { "name", "Bill" },
                new object[] { "name", "Paul" },
                new object[] { "name", "Steve" }

            };
        }

        private static Dictionary<string, StringValues> CreateDictionary(string key, string value)
        {
            var qs = new Dictionary<string, StringValues>
            {
                { key, value }
            };
            return qs;
        }

        public static HttpRequest CreateHttpRequest(string queryStringKey, string queryStringValue)
        {
            var context = new DefaultHttpContext();
            var request = context.Request;
            request.Query = new QueryCollection(CreateDictionary(queryStringKey, queryStringValue));
            return request;
        }

        public static ILogger CreateLogger(LoggerTypes type = LoggerTypes.Null)
        {
            ILogger logger;

            if (type == LoggerTypes.List)
            {
                logger = new ListLogger();
            }
            else
            {
                logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
            }

            return logger;
        }
    }
}

A TestFactory classe implementa os seguintes membros:The TestFactory class implements the following members:

  • Dados: Esta propriedade devolve uma recolha IEnumerable de dados de amostra.Data: This property returns an IEnumerable collection of sample data. Os pares de valor-chave representam valores que são passados para uma cadeia de consulta.The key value pairs represent values that are passed into a query string.

  • CreateDictionary: Este método aceita um par chave/valor como argumentos e devolve um novo Dictionary usado para criar para representar QueryCollection valores de cadeia de consulta.CreateDictionary: This method accepts a key/value pair as arguments and returns a new Dictionary used to create QueryCollection to represent query string values.

  • CreateHttpRequest: Este método cria um pedido HTTP inicializado com os parâmetros de cadeia de consulta.CreateHttpRequest: This method creates an HTTP request initialized with the given query string parameters.

  • CreateLogger: Com base no tipo madeirão, este método devolve uma classe de madeireiros utilizada para testes.CreateLogger: Based on the logger type, this method returns a logger class used for testing. O ListLogger registo de mensagens registadas disponível para avaliação em testes.The ListLogger keeps track of logged messages available for evaluation in tests.

Finalmente, crie uma nova classe em Funções.Testes projeto nomeado FunctionsTests.cs e introduza o seguinte código:Finally, create a new class in Functions.Tests project named FunctionsTests.cs and enter the following code:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Xunit;

namespace Functions.Tests
{
    public class FunctionsTests
    {
        private readonly ILogger logger = TestFactory.CreateLogger();

        [Fact]
        public async void Http_trigger_should_return_known_string()
        {
            var request = TestFactory.CreateHttpRequest("name", "Bill");
            var response = (OkObjectResult)await MyHttpTrigger.Run(request, logger);
            Assert.Equal("Hello, Bill. This HTTP triggered function executed successfully.", response.Value);
        }

        [Theory]
        [MemberData(nameof(TestFactory.Data), MemberType = typeof(TestFactory))]
        public async void Http_trigger_should_return_known_string_from_member_data(string queryStringKey, string queryStringValue)
        {
            var request = TestFactory.CreateHttpRequest(queryStringKey, queryStringValue);
            var response = (OkObjectResult)await MyHttpTrigger.Run(request, logger);
            Assert.Equal($"Hello, {queryStringValue}. This HTTP triggered function executed successfully.", response.Value);
        }

        [Fact]
        public void Timer_should_log_message()
        {
            var logger = (ListLogger)TestFactory.CreateLogger(LoggerTypes.List);
            MyTimerTrigger.Run(null, logger);
            var msg = logger.Logs[0];
            Assert.Contains("C# Timer trigger function executed at", msg);
        }
    }
}

Os membros implementados nesta classe são:The members implemented in this class are:

  • Http_trigger_should_return_known_string: Este teste cria um pedido com os valores de cadeia de consulta de name=Bill uma função HTTP e verifica se a resposta esperada é devolvida.Http_trigger_should_return_known_string: This test creates a request with the query string values of name=Bill to an HTTP function and checks that the expected response is returned.

  • Http_trigger_should_return_string_from_member_data: Este teste utiliza atributos xUnit para fornecer dados de amostra à função HTTP.Http_trigger_should_return_string_from_member_data: This test uses xUnit attributes to provide sample data to the HTTP function.

  • Timer_should_log_message: Este teste cria uma instância ListLogger de e passa-a para funções de temporizador.Timer_should_log_message: This test creates an instance of ListLogger and passes it to a timer functions. Uma vez executada a função, o registo é verificado para garantir que a mensagem esperada está presente.Once the function is run, then the log is checked to ensure the expected message is present.

Se pretender aceder às definições da aplicação nos seus testes, pode utilizar System.Environment.GetEnvironmentVariable.If you want to access application settings in your tests, you can use System.Environment.GetEnvironmentVariable.

Testes de execuçãoRun tests

Para realizar os testes, navegue no Explorador de Teste e clique em Executar tudo.To run the tests, navigate to the Test Explorer and click Run all.

Testar funções Azure com C# em Estúdio Visual

Testes de depurgaçãoDebug tests

Para depurar os testes, desfera um ponto de rutura num teste, navegue no Explorador de Teste e clique em Executar > Última Corrida de Debug.To debug the tests, set a breakpoint on a test, navigate to the Test Explorer and click Run > Debug Last Run.

JavaScript em Código VSJavaScript in VS Code

O exemplo a seguir descreve como criar uma aplicação JavaScript Function em VS Code e executar e testar com o Jest.The following example describes how to create a JavaScript Function app in VS Code and run and tests with Jest. Este procedimento utiliza a extensão vs Code Functions para criar funções Azure.This procedure uses the VS Code Functions extension to create Azure Functions.

Testar funções Azure com JavaScript em Código VS

ConfiguraçãoSetup

Para configurar o seu ambiente, inicialize uma nova aplicação Node.js numa pasta vazia executando npm init .To set up your environment, initialize a new Node.js app in an empty folder by running npm init.

npm init -y

Em seguida, instale o Jest executando o seguinte comando:Next, install Jest by running the following command:

npm i jest

Agora atualize package.js para substituir o comando de teste existente pelo seguinte comando:Now update package.json to replace the existing test command with the following command:

"scripts": {
    "test": "jest"
}

Criar módulos de testeCreate test modules

Com o projeto inicializado, pode criar os módulos utilizados para executar os testes automatizados.With the project initialized, you can create the modules used to run the automated tests. Comece por criar uma nova pasta chamada teste para manter os módulos de suporte.Begin by creating a new folder named testing to hold the support modules.

Na pasta de teste adicione um novo ficheiro, nomeie-o defaultContext.js, e adicione o seguinte código:In the testing folder add a new file, name it defaultContext.js, and add the following code:

module.exports = {
    log: jest.fn()
};

Este módulo ridiculariza a função de registo para representar o contexto de execução predefinido.This module mocks the log function to represent the default execution context.

Em seguida, adicione um novo ficheiro, nomeie-o defaultTimer.js, e adicione o seguinte código:Next, add a new file, name it defaultTimer.js, and add the following code:

module.exports = {
    IsPastDue: false
};

Este módulo implementa a IsPastDue propriedade para ficar é como uma instância de temporizador falso.This module implements the IsPastDue property to stand is as a fake timer instance. Configurações de temporizador como expressões NCRONTAB não são necessárias aqui, uma vez que o arnês de teste está simplesmente chamando a função diretamente para testar o resultado.Timer configurations like NCRONTAB expressions are not required here as the test harness is simply calling the function directly to test the outcome.

Em seguida, utilize a extensão vs Code Functions para criar uma nova função JAVAScript HTTP e nomeie-a HttpTrigger.Next, use the VS Code Functions extension to create a new JavaScript HTTP Function and name it HttpTrigger. Uma vez criada a função, adicione um novo ficheiro na mesma pasta denominada index.test.js, e adicione o seguinte código:Once the function is created, add a new file in the same folder named index.test.js, and add the following code:

const httpFunction = require('./index');
const context = require('../testing/defaultContext')

test('Http trigger should return known text', async () => {

    const request = {
        query: { name: 'Bill' }
    };

    await httpFunction(context, request);

    expect(context.log.mock.calls.length).toBe(1);
    expect(context.res.body).toEqual('Hello Bill');
});

A função HTTP do modelo devolve uma série de "Olá" concatenated com o nome fornecido na cadeia de consulta.The HTTP function from the template returns a string of "Hello" concatenated with the name provided in the query string. Este teste cria uma instância falsa de um pedido e passa-o para a função HTTP.This test creates a fake instance of a request and passes it to the HTTP function. O teste verifica se o método do registo é chamado uma vez e o texto devolvido é igual a "Olá Bill".The test checks that the log method is called once and the returned text equals "Hello Bill".

Em seguida, utilize a extensão vs Code Functions para criar uma nova Função de Temporizador JavaScript e nomeie-o TimerTrigger.Next, use the VS Code Functions extension to create a new JavaScript Timer Function and name it TimerTrigger. Uma vez criada a função, adicione um novo ficheiro na mesma pasta denominada index.test.js, e adicione o seguinte código:Once the function is created, add a new file in the same folder named index.test.js, and add the following code:

const timerFunction = require('./index');
const context = require('../testing/defaultContext');
const timer = require('../testing/defaultTimer');

test('Timer trigger should log message', () => {
    timerFunction(context, timer);
    expect(context.log.mock.calls.length).toBe(1);
});

A função temporizador do modelo regista uma mensagem no final do corpo da função.The timer function from the template logs a message at the end of the body of the function. Este teste garante que a função de registo é chamada uma vez.This test ensures the log function is called once.

Testes de execuçãoRun tests

Para realizar os testes, prima CTRL + ~ para abrir a janela de comando, e npm test executar:To run the tests, press CTRL + ~ to open the command window, and run npm test:

npm test

Testar funções Azure com JavaScript em Código VS

Testes de depurgaçãoDebug tests

Para depurar os seus testes, adicione a seguinte configuração à sua launch.jsno ficheiro:To debug your tests, add the following configuration to your launch.json file:

{
  "type": "node",
  "request": "launch",
  "name": "Jest Tests",
  "disableOptimisticBPs": true,
  "program": "${workspaceRoot}/node_modules/jest/bin/jest.js",
  "args": [
      "-i"
  ],
  "internalConsoleOptions": "openOnSessionStart"
}

Em seguida, desaponte um ponto de rutura no seu teste e prima F5.Next, set a breakpoint in your test and press F5.

Passos seguintesNext steps

Agora que aprendeu a escrever testes automatizados para as suas funções, continue com estes recursos:Now that you've learned how to write automated tests for your functions, continue with these resources: