Azure Functions에서 코드를 테스트하기 위한 전략Strategies for testing your code in Azure Functions

이 문서에서는 Azure Functions에 대한 자동화된 테스트를 만드는 방법에 대해 설명합니다.This article demonstrates how to create automated tests for Azure Functions.

모든 코드를 테스트하는 것이 좋지만, Functions의 논리를 래핑하고 함수 외부에 테스트를 만들면 최상의 결과를 얻을 수 있습니다.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. 논리를 무시하면 Functions의 코드 줄이 제한되고 함수가 단독으로 다른 클래스 또는 모듈을 호출할 수 있습니다.Abstracting logic away limits a Function's lines of code and allows the Function to be solely responsible for calling other classes or modules. 그러나이 문서에서는 HTTP 및 타이머 트리거 함수에 대해 자동화 된 테스트를 만드는 방법을 보여 줍니다.This article, however, demonstrates how to create automated tests against an HTTP and timer-triggered functions.

다음에 나오는 내용은 서로 다른 언어 및 환경을 대상으로 하는 두 가지 섹션으로 분할됩니다.The content that follows is split into two different sections meant to target different languages and environments. 테스트를 빌드하는 방법은 다음을 참조하세요.You can learn to build tests in:

샘플 리포지토리는 GitHub에서 사용할 수 있습니다.The sample repository is available on GitHub.

Visual Studio의 C#C# in Visual Studio

다음 예제에서는 Visual Studio에서 C# 함수 앱을 만들고 xUnit을 사용하여 실행 및 테스트하는 방법을 설명합니다.The following example describes how to create a C# Function app in Visual Studio and run and tests with xUnit.

Visual Studio의 C#을 사용하여 Azure Functions 테스트

설치 프로그램Setup

환경을 설정하려면 함수 및 테스트 앱을 만듭니다.To set up your environment, create a Function and test app. 다음 단계에서는 테스트를 지원하는 데 필요한 앱 및 함수를 만들 수 있습니다.The following steps help you create the apps and functions required to support the tests:

  1. 새 Functions 앱을 만들고 이름을 Functions로 지정합니다.Create a new Functions app and name it Functions
  2. 템플릿에서 HTTP 함수를 만들고 이름을 HttpTrigger로 지정합니다.Create an HTTP function from the template and name it HttpTrigger.
  3. 템플릿에서 타이머 함수를 만들고 이름을 TimerTrigger로 지정합니다.Create a timer function from the template and name it TimerTrigger.
  4. Visual Studio에서 파일 > 새로 만들기 > 프로젝트 > Visual C# > .NET Core > xUnit 테스트 프로젝트를 클릭하여 xUnit 테스트 앱을 만들고 이름을 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. NuGet을 사용 하 여 AspNetCore 에 테스트 앱의 참조를 추가 합니다.Use NuGet to add a reference from the test app to Microsoft.AspNetCore.Mvc
  6. Functions.Test 앱에서 Functions 앱을 참조합니다.Reference the Functions app from Functions.Test app.

테스트 클래스 만들기Create test classes

이제 애플리케이션이 만들어졌으므로 자동화된 테스트를 실행하는 데 사용되는 클래스를 만들 수 있습니다.Now that the applications are created, you can create the classes used to run the automated tests.

각 함수는 ILogger 인스턴스를 사용하여 메시지 로깅을 처리합니다.Each function takes an instance of ILogger to handle message logging. 일부 테스트는 메시지를 기록하지 않거나 로깅 구현 방법에 관여하지 않습니다.Some tests either don't log messages or have no concern for how logging is implemented. 기타 테스트는 테스트 통과 여부를 결정하기 위해 기록된 메시지를 평가해야 합니다.Other tests need to evaluate messages logged to determine whether a test is passing.

ListLogger 클래스는 ILogger 인터페이스를 구현 하 고 테스트 중에 평가할 메시지의 내부 목록을 보유 합니다.The ListLogger class implements the ILogger interface and holds an internal list of messages for evaluation during a test.

NullScope.cs 응용 프로그램을 마우스 오른쪽 단추로 클릭 하 고 추가 > 클래스를 선택 하 고 이름을 로 입력 한 후 다음 코드를 입력 합니다.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() { }
    }
}

그런 다음, ListLogger.cs 응용 프로그램을 마우스 오른쪽 단추로 클릭 하 고 추가 > 클래스를 선택 하 고 이름을 로 입력 한 후 다음 코드를 입력 합니다.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);
        }
    }
}

ListLogger 클래스는 ILogger 인터페이스에서 계약된 대로 다음 멤버를 구현합니다.The ListLogger class implements the following members as contracted by the ILogger interface:

  • Beginscope: 범위는 로깅에 컨텍스트를 추가 합니다.BeginScope: Scopes add context to your logging. 이 경우 테스트는 NullScope 클래스의 정적 인스턴스를 가리키며 테스트가 작동할 수 있도록 합니다.In this case, the test just points to the static instance on the NullScope class to allow the test to function.

  • IsEnabled: false의 기본값이 제공 됩니다.IsEnabled: A default value of false is provided.

  • 로그:이 메서드는 제공 된 formatter 함수를 사용 하 여 메시지의 서식을 지정한 다음 결과 텍스트를 Logs 컬렉션에 추가 합니다.Log: This method uses the provided formatter function to format the message and then adds the resulting text to the Logs collection.

Logs 컬렉션은 List<string>의 인스턴스이고 생성자에서 초기화됩니다.The Logs collection is an instance of List<string> and is initialized in the constructor.

그런 다음, Functions.Test 애플리케이션을 마우스 오른쪽 단추로 클릭하고, 추가 > 클래스를 선택하고, 이름을 LoggerTypes.cs로 지정하고, 다음 코드를 입력합니다.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
    }
}

이 열거형은 테스트에서 사용하는 로거 형식을 지정합니다.This enumeration specifies the type of logger used by the tests.

그런 다음, Functions.Test 애플리케이션을 마우스 오른쪽 단추로 클릭하고, 추가 > 클래스를 선택하고, 이름을 TestFactory.cs로 지정하고, 다음 코드를 입력합니다.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;
        }
    }
}

TestFactory 클래스는 다음 멤버를 구현합니다.The TestFactory class implements the following members:

  • 데이터:이 속성은 예제 데이터의 IEnumerable 컬렉션을 반환 합니다.Data: This property returns an IEnumerable collection of sample data. 키 값 쌍은 쿼리 문자열로 전달되는 값을 나타냅니다.The key value pairs represent values that are passed into a query string.

  • CreateDictionary:이 메서드는 키/값 쌍을 인수로 수락 하 고 쿼리 문자열 값을 나타내는 QueryCollection를 만드는 데 사용 되는 새 Dictionary을 반환 합니다.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:이 메서드는 지정 된 쿼리 문자열 매개 변수를 사용 하 여 초기화 된 HTTP 요청을 만듭니다.CreateHttpRequest: This method creates an HTTP request initialized with the given query string parameters.

  • Createlogger:로 거 형식을 기반으로 하는이 메서드는 테스트에 사용 되는로 거 클래스를 반환 합니다.CreateLogger: Based on the logger type, this method returns a logger class used for testing. ListLogger는 테스트에서 평가에 사용할 수 있는 기록된 메시지를 추적합니다.The ListLogger keeps track of logged messages available for evaluation in tests.

그런 다음, Functions.Test 애플리케이션을 마우스 오른쪽 단추로 클릭하고, 추가 > 클래스를 선택하고, 이름을 FunctionsTests.cs로 지정하고, 다음 코드를 입력합니다.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 HttpTrigger.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 HttpTrigger.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);
        }
    }
}

이 클래스에 구현된 멤버는 다음과 같습니다.The members implemented in this class are:

  • Http_trigger_should_return_known_string:이 테스트는 Http 함수에 name=Bill의 쿼리 문자열 값이 포함 된 요청을 만들고 예상 응답이 반환 되는지 확인 합니다.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:이 테스트는 xunit 특성을 사용 하 여 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:이 테스트는 ListLogger 인스턴스를 만들어 타이머 함수에 전달 합니다.Timer_should_log_message: This test creates an instance of ListLogger and passes it to a timer functions. 함수가 실행되면 로그를 확인하여 예상 메시지가 있는지 확인합니다.Once the function is run, then the log is checked to ensure the expected message is present.

테스트에서 응용 프로그램 설정에 액세스 하려는 경우 GetEnvironmentVariable를 사용할 수 있습니다.If you want to access application settings in your tests, you can use System.Environment.GetEnvironmentVariable.

테스트 실행Run tests

테스트를 실행하려면 테스트 탐색기로 이동하고 모두 실행을 클릭합니다.To run the tests, navigate to the Test Explorer and click Run all.

Visual Studio의 C#을 사용하여 Azure Functions 테스트

테스트 디버그Debug tests

테스트를 디버그하려면 테스트에 중단점을 설정하고, 테스트 탐색기로 이동하고, 실행 > 마지막 실행 디버그를 클릭합니다.To debug the tests, set a breakpoint on a test, navigate to the Test Explorer and click Run > Debug Last Run.

VS Code의 JavaScriptJavaScript in VS Code

다음 예제에서는 VS Code에서 JavaScript 함수 앱을 만들고 Jest를 사용하여 실행 및 테스트하는 방법을 설명합니다.The following example describes how to create a JavaScript Function app in VS Code and run and tests with Jest. 이 프로시저는 VS Code Functions 확장을 사용하여 Azure Functions를 만듭니다.This procedure uses the VS Code Functions extension to create Azure Functions.

VS Code의 JavaScript를 사용하여 Azure Functions 테스트

설치 프로그램Setup

환경을 설정하려면 npm init를 실행하여 빈 폴더에서 새 Node.js 앱을 초기화합니다.To set up your environment, initialize a new Node.js app in an empty folder by running npm init.

npm init -y

다음으로, 다음 명령을 실행하여 Jest를 설치합니다.Next, install Jest by running the following command:

npm i jest

이제 _package.json_을 업데이트하여 기존 테스트 명령을 다음 명령으로 바꿉니다.Now update package.json to replace the existing test command with the following command:

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

테스트 모듈 만들기Create test modules

프로젝트가 초기화된 상태에서 자동화된 테스트를 실행하는 데 사용되는 모듈을 만들 수 있습니다.With the project initialized, you can create the modules used to run the automated tests. 먼저 지원 모듈을 포함할 testing이라는 새 폴더를 만듭니다.Begin by creating a new folder named testing to hold the support modules.

testing 폴더에서 새 파일을 추가하고, 이름을 defaultContext.js로 지정하고, 다음 코드를 추가합니다.In the testing folder add a new file, name it defaultContext.js, and add the following code:

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

이 모듈은 기본 실행 컨텍스트를 나타내는 log 함수를 모방합니다.This module mocks the log function to represent the default execution context.

다음으로, 새 파일을 추가하고, 이름을 defaultTimer.js로 지정하고, 다음 코드를 추가합니다.Next, add a new file, name it defaultTimer.js, and add the following code:

module.exports = {
    IsPastDue: false
};

이 모듈은 가짜 타이머 인스턴스인 is를 나타내는 IsPastDue 속성을 구현합니다.This module implements the IsPastDue property to stand is as a fake timer instance. 테스트 도구는 단순히 함수를 직접 호출 하 여 결과를 테스트 하는 것 이므로 NCRONTAB 식과 같은 타이머 구성은 필요 하지 않습니다.Timer configurations like NCRONTAB expressions are not required here as the test harness is simply calling the function directly to test the outcome.

그런 다음, VS Code Functions 확장을 사용하여 새 JavaScript HTTP 함수를 만들고 이름을 HttpTrigger로 지정합니다.Next, use the VS Code Functions extension to create a new JavaScript HTTP Function and name it HttpTrigger. 함수가 만들어지면 index.test.js라는 동일한 폴더에 새 파일을 추가하고 다음 코드를 추가합니다.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');
});

템플릿의 HTTP 함수는 쿼리 문자열에 제공된 이름과 연결된 “Hello” 문자열을 반환합니다.The HTTP function from the template returns a string of "Hello" concatenated with the name provided in the query string. 이 테스트는 요청의 가짜 인스턴스를 만들고 HTTP 함수로 전달합니다.This test creates a fake instance of a request and passes it to the HTTP function. 테스트는 log 메서드가 한 번 호출되고 반환된 텍스트가 “Hello Bill”과 같은지 확인합니다.The test checks that the log method is called once and the returned text equals "Hello Bill".

그런 다음, VS Code Functions 확장을 사용하여 새 JavaScript 타이머 함수를 만들고 이름을 TimerTrigger로 지정합니다.Next, use the VS Code Functions extension to create a new JavaScript Timer Function and name it TimerTrigger. 함수가 만들어지면 index.test.js라는 동일한 폴더에 새 파일을 추가하고 다음 코드를 추가합니다.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);
});

템플릿의 타이머 함수는 함수 본문 끝에 메시지를 기록합니다.The timer function from the template logs a message at the end of the body of the function. 이 테스트는 log 함수가 한 번 호출되었는지 확인합니다.This test ensures the log function is called once.

테스트 실행Run tests

테스트를 실행하려면 Ctrl+~ 를 눌러 명령 창을 열고 npm test를 실행합니다.To run the tests, press CTRL + ~ to open the command window, and run npm test:

npm test

VS Code의 JavaScript를 사용하여 Azure Functions 테스트

테스트 디버그Debug tests

테스트를 디버그하려면 launch.json 파일에 다음 구성을 추가합니다.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"
}

그런 다음, 테스트에 중단점을 설정하고 F5 키를 누릅니다.Next, set a breakpoint in your test and press F5.

다음 단계Next steps

이제 함수에 대한 자동화된 테스트를 작성하는 방법을 알아보았으므로 다음 리소스를 계속 진행합니다.Now that you've learned how to write automated tests for your functions, continue with these resources: