Strategie per il test del codice in Funzioni di AzureStrategies for testing your code in Azure Functions

Questo articolo illustra come creare i test automatizzati per le Funzioni di Azure.This article demonstrates how to create automated tests for Azure Functions.

Si consiglia di testare tutto il codice, tuttavia si potrebbero ottenere risultati migliori eseguendo il wrapping di una logica della funzione e creando dei test all'esterno della funzione.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. Eseguendo subito l'astrazione per la logica si limitano le righe di una funzione di codice e si consente alla funzione di assumere la piena responsabilità per la chiamata ad altre classi o moduli.Abstracting logic away limits a Function's lines of code and allows the Function to be solely responsible for calling other classes or modules. Questo articolo, tuttavia, illustra come creare test automatizzati in un HTTP e la funzione attivata tramite timer.This article, however, demonstrates how to create automated tests against an HTTP and timer-triggered function.

Il contenuto seguente è suddiviso in due sezioni diverse con lo scopo di ottenere diversi linguaggi e ambienti di destinazione.The content that follows is split into two different sections meant to target different languages and environments. È possibile imparare a compilare i test in:You can learn to build tests in:

Il repository di esempio è disponibile in GitHub.The sample repository is available on GitHub.

C# in Visual StudioC# in Visual Studio

Il seguente esempio illustra come creare un'app della funzione C# in Visual Studio ed eseguire i test con xUnit.The following example describes how to create a C# Function app in Visual Studio and run and tests with xUnit.

Test di Funzioni di Azure con C# in Visual Studio

ConfigurazioneSetup

Per configurare l'ambiente, creare una funzione e testare l'app.To set up your environment, create a Function and test app. I passaggi seguenti consentono di creare le app e le funzioni necessarie per supportare i test:The following steps help you create the apps and functions required to support the tests:

  1. Creare una nuova app funzioni e denominarla FunzioniCreate a new Functions app and name it Functions
  2. Creare una funzione HTTP dal modello e denominarla HttpTrigger.Create an HTTP function from the template and name it HttpTrigger.
  3. Creare una funzione del timer dal modello e denominarla TimerTrigger.Create a timer function from the template and name it TimerTrigger.
  4. Creare un'app di test xUnit in Visual Studio facendo clic su File > Nuovo > Progetto > Visual C# > .NET Core > Progetto di test xUnit e denominarlo Functions.Test.Create an xUnit Test app in Visual Studio by clicking File > New > Project > Visual C# > .NET Core > xUnit Test Project and name it Functions.Test.
  5. Usare NuGet per aggiungere riferimenti dall'app di test Microsoft. AspNetCore. MvcUse Nuget to add a references from the test app Microsoft.AspNetCore.Mvc
  6. Fare riferimento all'app Funzioni dall'app Functions.Test.Reference the Functions app from Functions.Test app.

Crea classi di testCreate test classes

Ora che vengono create le applicazioni, è possibile creare le classi usate per eseguire i test automatizzati.Now that the applications are created, you can create the classes used to run the automated tests.

Ogni funzione accetta un'istanza di ILogger per gestire la registrazione dei messaggi.Each function takes an instance of ILogger to handle message logging. Alcuni test non registrano messaggi oppure non hanno alcun problema per la modalità di implementazione della registrazione.Some tests either don't log messages or have no concern for how logging is implemented. Altri test devono valutare i messaggi registrati per determinare se si sta passando un test.Other tests need to evaluate messages logged to determine whether a test is passing.

La classe ListLogger è destinata a implementare l'interfaccia ILogger e a mantenere l'elenco interno dei messaggi per la valutazione durante un test.The ListLogger class is meant to implement the ILogger interface and hold in internal list of messages for evaluation during a test.

Fare clic con il pulsante destro del mouse sull'applicazione Functions. test e scegliere Aggiungi > Class, denominarla NullScope.cs e immettere il codice seguente:Right-click on the Functions.Test application and select Add > Class, name it 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() { }
    }
}

Fare quindi clic con il pulsante destro del mouse sull'applicazione Functions. test e scegliere Aggiungi > Class, denominarla ListLogger.cs e immettere il codice seguente:Next, right-click on the Functions.Test application and select Add > Class, name it 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);
        }
    }
}

La classe ListLogger implementa i membri seguenti come contrattato dall'interfaccia ILogger:The ListLogger class implements the following members as contracted by the ILogger interface:

  • BeginScope: gli ambiti aggiungono il contesto alla registrazione.BeginScope: Scopes add context to your logging. In questo caso, il test punta solo all'istanza statica nella classe NullScope per consentire il funzionamento del test.In this case, the test just points to the static instance on the NullScope class to allow the test to function.

  • IsEnabled: viene fornito un valore predefinito di false.IsEnabled: A default value of false is provided.

  • Log: questo metodo usa la funzione formatter fornita per formattare il messaggio e quindi aggiunge il testo risultante alla raccolta di Logs.Log: This method uses the provided formatter function to format the message and then adds the resulting text to the Logs collection.

La raccolta Logs è un'istanza di List<string> e viene inizializzata nel costruttore.The Logs collection is an instance of List<string> and is initialized in the constructor.

In seguito, fare doppio clic sull'applicazione Functions.Test e selezionare Aggiungi > Classe, denominarla LoggerTypes.cs e immettere il codice seguente:Next, right-click on the Functions.Test application and select Add > Class, name it LoggerTypes.cs and enter the following code:

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

Questa enumerazione specifica il tipo di logger usato dai test.This enumeration specifies the type of logger used by the tests.

In seguito, fare doppio clic sull'applicazione Functions.Test e selezionare Aggiungi > Classe, denominarla TestFactory.cs e immettere il codice seguente:Next, right-click on the Functions.Test application and select Add > Class, name it 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 DefaultHttpRequest CreateHttpRequest(string queryStringKey, string queryStringValue)
        {
            var request = new DefaultHttpRequest(new DefaultHttpContext())
            {
                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;
        }
    }
}

La classe TestFactory implementa i seguenti membri:The TestFactory class implements the following members:

  • Data: questa proprietà restituisce una raccolta di dati di esempio IEnumerable .Data: This property returns an IEnumerable collection of sample data. Le coppie chiave-valore rappresentano valori che vengono passati in una stringa di query.The key value pairs represent values that are passed into a query string.

  • CreateDictionary: questo metodo accetta una coppia chiave/valore come argomenti e restituisce un nuovo Dictionary usato per creare QueryCollection per rappresentare i valori della stringa di query.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: questo metodo crea una richiesta http inizializzata con i parametri della stringa di query specificati.CreateHttpRequest: This method creates an HTTP request initialized with the given query string parameters.

  • CreateLogger: in base al tipo di logger, questo metodo restituisce una classe logger utilizzata per il testing.CreateLogger: Based on the logger type, this method returns a logger class used for testing. ListLogger tiene traccia dei messaggi registrati disponibili per la valutazione nei test.The ListLogger keeps track of logged messages available for evaluation in tests.

In seguito, fare doppio clic sull'applicazione Functions.Test e selezionare Aggiungi > Classe, denominarla FunctionsTests.cs e immettere il codice seguente:Next, right-click on the Functions.Test application and select Add > Class, name it 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 HttpFunction.Run(request, logger);
            Assert.Equal("Hello, Bill", 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 HttpFunction.Run(request, logger);
            Assert.Equal($"Hello, {queryStringValue}", response.Value);
        }

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

I membri implementati in questa classe sono:The members implemented in this class are:

  • Http_trigger_should_return_known_string: questo test crea una richiesta con i valori della stringa di query di name=Bill a una funzione http e verifica che venga restituita la risposta prevista.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: questo test usa gli attributi xUnit per fornire dati di esempio alla funzione 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: questo test crea un'istanza di ListLogger e la passa a una funzione timer.Timer_should_log_message: This test creates an instance of ListLogger and passes it to a timer functions. Una volta eseguita la funzione, il log viene controllato per verificare che sia presente il messaggio previsto.Once the function is run, then the log is checked to ensure the expected message is present.

Se si desidera accedere alle impostazioni dell'applicazione nei test, è possibile utilizzare System. Environment. GetEnvironmentVariable.If you want to access application settings in your tests, you can use System.Environment.GetEnvironmentVariable.

Esecuzione dei testRun tests

Per eseguire i test, passare al Explorer di Test e fare clic su Esegui tutto.To run the tests, navigate to the Test Explorer and click Run all.

Test di Funzioni di Azure con C# in Visual Studio

Esecuzione del debug dei testDebug tests

Per eseguire il debug dei test, impostare un punto di interruzione in un test, passare a Explorer del Test e fare clic su Esegui > Ultima esecuzione del Debug.To debug the tests, set a breakpoint on a test, navigate to the Test Explorer and click Run > Debug Last Run.

JavaScript in Visual Studio CodeJavaScript in VS Code

Il seguente esempio illustra come creare un'app della funzione di JavaScript in Visual Studio Code ed eseguire i test con Jest.The following example describes how to create a JavaScript Function app in VS Code and run and tests with Jest. Questa procedura usa l'estensione delle funzioni di Visual Studio Code per creare le Funzioni di Azure.This procedure uses the VS Code Functions extension to create Azure Functions.

Eseguire il test delle Funzioni di Azure con JavaScript in Visual Studio Code

ConfigurazioneSetup

Per configurare l'ambiente, inizializzare una nuova app Node.js in una cartella vuota eseguendo npm init.To set up your environment, initialize a new Node.js app in an empty folder by running npm init.

npm init -y

In seguito, installare Jest eseguendo il comando seguente:Next, install Jest by running the following command:

npm i jest

A questo punto aggiornare package. JSON per sostituire il comando test esistente con il comando seguente:Now update package.json to replace the existing test command with the following command:

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

Creare moduli del testCreate test modules

Con il progetto inizializzato, è possibile creare i moduli usati per eseguire i test automatizzati.With the project initialized, you can create the modules used to run the automated tests. Iniziare creando una nuova cartella denominata testing per contenere i moduli di supporto.Begin by creating a new folder named testing to hold the support modules.

Nella cartella testing aggiungere un nuovo file, denominarla defaultContext.jse aggiungere il codice seguente:In the testing folder add a new file, name it defaultContext.js, and add the following code:

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

Questo modulo simula la funzione log per rappresentare il contesto di esecuzione predefinito.This module mocks the log function to represent the default execution context.

Successivamente, aggiungere un nuovo file, denominarlo defaultTimer.jse aggiungere il codice seguente:Next, add a new file, name it defaultTimer.js, and add the following code:

module.exports = {
    IsPastDue: false
};

Questo modulo implementa la proprietà IsPastDue per realizzare che è come un'istanza del timer fittizia.This module implements the IsPastDue property to stand is as a fake timer instance.

Successivamente, usare l'estensione delle Funzioni di Visual Studio Code per creare una nuova funzione HTTP JavaScript e denominarla HttpTrigger.Next, use the VS Code Functions extension to create a new JavaScript HTTP Function and name it HttpTrigger. Dopo aver creato la funzione, aggiungere un nuovo file nella stessa cartella denominata index.test.js e aggiungere il codice seguente: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');
});

La funzione HTTP dal modello restituisce una stringa di "Hello" concatenati con il nome specificato nella stringa di query.The HTTP function from the template returns a string of "Hello" concatenated with the name provided in the query string. Questo test consente di creare un'istanza fittizia di una richiesta e la passa alla funzione HTTP.This test creates a fake instance of a request and passes it to the HTTP function. Il test verifica che il metodo log venga chiamato una sola volta e che il testo restituito sia uguale a "Hello Bill".The test checks that the log method is called once and the returned text equals "Hello Bill".

Successivamente, usare l'estensione delle Funzioni di Visual Studio Code per creare una nuova funzione timer JavaScript e denominarla TimerTrigger.Next, use the VS Code Functions extension to create a new JavaScript Timer Function and name it TimerTrigger. Dopo aver creato la funzione, aggiungere un nuovo file nella stessa cartella denominata index.test.js e aggiungere il codice seguente: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);
});

La funzione timer dal modello registra un messaggio alla fine del corpo della funzione.The timer function from the template logs a message at the end of the body of the function. Questo test assicura che la funzione log venga chiamata una sola volta.This test ensures the log function is called once.

Esecuzione dei testRun tests

Per eseguire i test, premere CTRL + ~ per aprire la finestra di comando ed eseguire npm test:To run the tests, press CTRL + ~ to open the command window, and run npm test:

npm test

Eseguire il test delle Funzioni di Azure con JavaScript in Visual Studio Code

Esecuzione del debug dei testDebug tests

Per eseguire il debug dei test, aggiungere la configurazione seguente per il file launch.json file: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"
}

Successivamente, impostare un punto di interruzione del test e premere F5.Next, set a breakpoint in your test and press F5.

Passaggi successiviNext steps

Ora che si è appreso come scrivere i test automatizzati per le funzioni, continuare con queste risorse:Now that you've learned how to write automated tests for your functions, continue with these resources: