봇을 단위 테스트하는 방법

적용 대상: SDK v4

이 항목에서는 다음 방법을 보여 드리겠습니다.

  • 봇에 대한 단위 테스트를 만듭니다.
  • 어설션을 사용하여 대화 상자에서 반환된 활동에 대해 예상 값에 대해 검사.
  • 어설션을 사용하여 대화 상자에서 반환된 결과를 검사.
  • 다양한 유형의 데이터 기반 테스트를 만듭니다.
  • 언어 인식기 등 대화 상자의 다양한 종속성에 대한 모의 개체를 만듭니다.

필수 조건

이 항목에 사용된 CoreBot 테스트 샘플은 단위 테스트를 만들기 위해 Microsoft.Bot.Builder.Testing 패키지, XUnitMoq를 참조합니다.

핵심 봇 샘플은 LUIS(Language Understanding)를 사용하여 사용자 의도를 식별합니다. 그러나 사용자 의도를 식별하는 것은 이 문서의 초점이 아닙니다. 사용자 의도 를 식별하는 방법에 대한 자세한 내용은 자연어 이해에 자연어 이해 추가를 참조하세요.

참고 항목

LUIS(Language Understanding)는 2025년 10월 1일에 사용 중지됩니다. 2023년 4월 1일부터 새 LUIS 리소스를 만들 수 없습니다. 이제 최신 버전의 언어 이해가 Azure AI Language의 일부로 제공됩니다.

Azure AI Language의 기능인 CLU(대화형 언어 이해)는 업데이트된 LUIS 버전입니다. Bot Framework SDK의 언어 이해 지원에 대한 자세한 내용은 자연어 이해를 참조하세요.

테스트 대화 상자

CoreBot 샘플에서 대화 상자는 클래스를 통해 DialogTestClient 단위 테스트됩니다. 이 메커니즘은 봇 외부에서 격리된 상태에서 웹 서비스에 코드를 배포하지 않고도 테스트하는 메커니즘을 제공합니다.

이 클래스를 사용하여 턴 바이 턴 기준으로 대화 상자 응답의 유효성을 검사하는 단위 테스트를 작성할 수 있습니다. 클래스를 사용하는 DialogTestClient 단위 테스트는 botbuilder 대화 상자 라이브러리를 사용하여 빌드된 다른 대화 상자에서 작동해야 합니다.

다음 예제에서는 다음에서 DialogTestClient파생된 테스트를 보여 줍니다.

var sut = new BookingDialog();
var testClient = new DialogTestClient(Channels.Msteams, sut);

var reply = await testClient.SendActivityAsync<IMessageActivity>("hi");
Assert.Equal("Where would you like to travel to?", reply.Text);

reply = await testClient.SendActivityAsync<IMessageActivity>("Seattle");
Assert.Equal("Where are you traveling from?", reply.Text);

reply = await testClient.SendActivityAsync<IMessageActivity>("New York");
Assert.Equal("When would you like to travel?", reply.Text);

reply = await testClient.SendActivityAsync<IMessageActivity>("tomorrow");
Assert.Equal("OK, I will book a flight from Seattle to New York for tomorrow, Is this Correct?", reply.Text);

reply = await testClient.SendActivityAsync<IMessageActivity>("yes");
Assert.Equal("Sure thing, wait while I finalize your reservation...", reply.Text);

reply = testClient.GetNextReply<IMessageActivity>();
Assert.Equal("All set, I have booked your flight to Seattle for tomorrow", reply.Text);

클래스는 DialogTestClient 네임스페이 Microsoft.Bot.Builder.Testing 스에 정의되며 Microsoft.Bot.Builder.Testing NuGet 패키지에 포함됩니다.

DialogTestClient

첫 번째 매개 변수 DialogTestClient 는 대상 채널입니다. 이를 통해 봇의 대상 채널(Teams, Slack 등)에 따라 다양한 렌더링 논리를 테스트할 수 있습니다. 대상 채널에 대해 확실하지 않은 경우 또는 Test 채널 ID를 사용할 Emulator 수 있지만 일부 구성 요소는 현재 채널에 따라 다르게 동작할 수 있습니다. 예를 들어 ConfirmPrompt 예/아니요 옵션은 채널 및 Emulator 채널에 Test 대해 다르게 렌더링됩니다. 이 매개 변수를 사용하여 채널 ID를 기반으로 대화 상자에서 조건부 렌더링 논리를 테스트할 수도 있습니다.

두 번째 매개 변수는 테스트 중인 대화 상자의 인스턴스입니다. 이 문서의 sut 샘플 코드에서 테스트 중인 시스템을 나타냅니다.

DialogTestClient 생성자는 클라이언트 동작을 추가로 사용자 지정하거나 필요한 경우 테스트 중인 대화 상자에 매개 변수를 전달할 수 있는 추가 매개 변수를 제공합니다. 대화 상자에 대한 초기화 데이터를 전달하거나, 사용자 지정 미들웨어를 추가하거나, 고유한 TestAdapter 및 ConversationState 인스턴스를 사용할 수 있습니다.

메시지 보내기 및 받기

SendActivityAsync<IActivity> 메서드를 사용하여 대화 상자에 텍스트 발화 또는 IActivity를 보내고 대화 상자가 첫 번째로 수신하는 메시지를 반환할 수 있습니다. <T> 매개 변수는 응답을 캐스팅할 필요 없이 어설션할 수 있도록 강력한 형식의 응답 인스턴스를 반환하는 데 사용됩니다.

var reply = await testClient.SendActivityAsync<IMessageActivity>("hi");
Assert.Equal("Where would you like to travel to?", reply.Text);

일부 시나리오에서는 봇이 단일 활동에 대한 응답으로 여러 메시지를 보낼 수 있습니다. 이 경우 DialogTestClient는 응답을 큐에 추가하며 사용자는 GetNextReply<IActivity> 메서드를 사용하여 응답 큐의 다음 메시지를 팝할 수 있습니다.

reply = testClient.GetNextReply<IMessageActivity>();
Assert.Equal("All set, I have booked your flight to Seattle for tomorrow", reply.Text);

GetNextReply<IActivity> 는 응답 큐에 추가 메시지가 없는 경우 null을 반환합니다.

활동 어설션

CoreBot 샘플의 코드는 반환된 Text 활동의 속성만 어설션합니다. 더 복잡한 봇에서는 등과 같은 SpeakInputHintChannelData다른 속성을 어설션할 수 있습니다.

Assert.Equal("Sure thing, wait while I finalize your reservation...", reply.Text);
Assert.Equal("One moment please...", reply.Speak);
Assert.Equal(InputHints.IgnoringInput, reply.InputHint);

위와 같이 각 속성을 개별적으로 검사 작업을 어설션하기 위해 고유한 도우미 유틸리티를 작성하거나 FluentAssertions와 같은 다른 프레임워크를 사용하여 사용자 지정 어설션을 작성하고 테스트 코드를 간소화할 수 있습니다.

대화 상자에 매개 변수 전달

생성자에는 DialogTestClient 매개 변수를 initialDialogOptions 대화 상자에 전달하는 데 사용할 수 있는 항목이 있습니다. 예를 들어 MainDialog 이 샘플에서는 사용자의 발언에서 확인하는 엔터티를 사용하여 언어 인식 결과에서 개체를 초기화 BookingDetails 하고 호출에 이 개체를 전달하여 호출 BookingDialog합니다.

다음과 같이 테스트에서 이를 구현할 수 있습니다.

var inputDialogParams = new BookingDetails()
{
    Destination = "Seattle",
    TravelDate = $"{DateTime.UtcNow.AddDays(1):yyyy-MM-dd}"
};

var sut = new BookingDialog();
var testClient = new DialogTestClient(Channels.Msteams, sut, inputDialogParams);

BookingDialog 는 이 매개 변수를 수신하고 테스트에서 호출 MainDialog할 때와 동일한 방식으로 액세스합니다.

private async Task<DialogTurnResult> DestinationStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
    var bookingDetails = (BookingDetails)stepContext.Options;
    ...
}

대화 상자 턴 결과 어설션

일부 대화 상자는 호출 대화 상자의 값을 좋아 BookingDialog 하거나 DateResolverDialog 반환합니다. 개체는 DialogTestClient 대화 상자에서 DialogTurnResult 반환된 결과를 분석하고 어설션하는 데 사용할 수 있는 속성을 노출합니다.

예시:

var sut = new BookingDialog();
var testClient = new DialogTestClient(Channels.Msteams, sut);

var reply = await testClient.SendActivityAsync<IMessageActivity>("hi");
Assert.Equal("Where would you like to travel to?", reply.Text);

...

var bookingResults = (BookingDetails)testClient.DialogTurnResult.Result;
Assert.Equal("New York", bookingResults?.Origin);
Assert.Equal("Seattle", bookingResults?.Destination);
Assert.Equal("2019-06-21", bookingResults?.TravelDate);

DialogTurnResult 속성을 사용하여 폭포의 단계에서 반환된 중간 결과를 검사하고 어설션할 수도 있습니다.

테스트 출력 분석

경우에 따라 테스트를 디버그하지 않고도 테스트 실행을 분석하기 위해 단위 테스트 기록을 읽어야 합니다.

Microsoft.Bot.Builder.Testing 패키지에는 대화 상자에서 보내고 받은 메시지를 콘솔에 기록하는 메시지가 포함되어 XUnitDialogTestLogger 있습니다.

이 미들웨어를 사용하려면 테스트에서 XUnit 테스트 실행기에서 제공하는 개체를 수신 ITestOutputHelper 하는 생성자를 노출하고 매개 변수를 XUnitDialogTestLogger 통해 middlewares 전달 DialogTestClient 될 생성자를 만들어야 합니다.

public class BookingDialogTests
{
    private readonly IMiddleware[] _middlewares;

    public BookingDialogTests(ITestOutputHelper output)
        : base(output)
    {
        _middlewares = new[] { new XUnitDialogTestLogger(output) };
    }

    [Fact]
    public async Task SomeBookingDialogTest()
    {
        // Arrange
        var sut = new BookingDialog();
        var testClient = new DialogTestClient(Channels.Msteams, sut, middlewares: _middlewares);

        ...
    }
}

다음은 출력 창이 XUnitDialogTestLogger 구성되면 출력 창에 로그하는 내용의 예입니다.

Example middleware output from XUnit.

XUnit을 사용할 때 콘솔에 테스트 출력을 보내는 방법에 대한 자세한 내용은 XUnit 설명서의 출력 캡처를 참조하세요.

이 출력은 연속 통합 빌드 중에 빌드 서버에 기록되며 빌드 실패를 분석하는 데 도움이 됩니다.

데이터 기반 테스트

대부분의 경우 대화 논리는 변경되지 않으며 대화의 다른 실행 경로는 사용자 발화를 기반으로 합니다. 대화에서 각 변형에 대해 단일 단위 테스트를 작성하는 대신 데이터 기반 테스트(매개 변수가 있는 테스트라고도 함)를 사용하는 것이 더 쉽습니다.

예를 들어 이 문서의 개요 섹션에 있는 샘플 테스트는 실행 흐름을 테스트하는 방법을 보여 주지만 다음과 같은 다른 실행 흐름은 테스트하지 않습니다.

  • 사용자가 확인에 '아니오'라고 말하면 어떻게 되나요?
  • 다른 날짜를 사용하는 경우 어떻게 해야 할까요?

데이터 기반 테스트를 사용하면 테스트를 다시 작성할 필요 없이 이 모든 순열을 테스트할 수 있습니다.

CoreBot 샘플에서는 XUnit의 Theory 테스트를 사용하여 테스트를 매개 변수화합니다.

InlineData를 사용한 이론 테스트

다음 테스트는 사용자가 "cancel"이면 대화 상자가 취소되는 것을 검사.

[Fact]
public async Task ShouldBeAbleToCancel()
{
    var sut = new TestCancelAndHelpDialog();
    var testClient = new DialogTestClient(Channels.Test, sut);

    var reply = await testClient.SendActivityAsync<IMessageActivity>("Hi");
    Assert.Equal("Hi there", reply.Text);
    Assert.Equal(DialogTurnStatus.Waiting, testClient.DialogTurnResult.Status);

    reply = await testClient.SendActivityAsync<IMessageActivity>("cancel");
    Assert.Equal("Cancelling...", reply.Text);
}

대화 상자를 취소하려면 사용자가 "종료", "신경 쓰지 마세요" 및 "중지"를 입력할 수 있습니다. 가능한 모든 단어에 대해 새 테스트 사례를 작성하는 대신 값 목록을 InlineData 통해 매개 변수를 허용하는 단일 Theory 테스트 메서드를 작성하여 각 테스트 사례에 대한 매개 변수를 정의합니다.

[Theory]
[InlineData("cancel")]
[InlineData("quit")]
[InlineData("never mind")]
[InlineData("stop it")]
public async Task ShouldBeAbleToCancel(string cancelUtterance)
{
    var sut = new TestCancelAndHelpDialog();
    var testClient = new DialogTestClient(Channels.Test, sut, middlewares: _middlewares);

    var reply = await testClient.SendActivityAsync<IMessageActivity>("Hi");
    Assert.Equal("Hi there", reply.Text);
    Assert.Equal(DialogTurnStatus.Waiting, testClient.DialogTurnResult.Status);

    reply = await testClient.SendActivityAsync<IMessageActivity>(cancelUtterance);
    Assert.Equal("Cancelling...", reply.Text);
}

새 테스트는 서로 다른 매개 변수를 사용하여 네 번 실행되며 각 사례는 Visual Studio 테스트 탐색기의 테스트 아래에 ShouldBeAbleToCancel 자식 항목으로 표시됩니다. 아래와 같이 실패하는 경우 전체 테스트 집합을 다시 실행하지 않고 실패한 시나리오를 마우스 오른쪽 단추로 클릭하고 디버그할 수 있습니다.

Example test results for in-line data.

MemberData 및 복합 형식을 사용하는 이론 테스트

InlineData 는 간단한 값 형식 매개 변수(문자열, int 등)를 수신하는 작은 데이터 기반 테스트에 유용합니다.

개체 BookingDialogBookingDetails 받고 새 BookingDetails 개체를 반환합니다. 이 대화 상자의 매개 변수 없는 테스트 버전은 다음과 같습니다.

[Fact]
public async Task DialogFlow()
{
    // Initial parameters
    var initialBookingDetails = new BookingDetails
    {
        Origin = "Seattle",
        Destination = null,
        TravelDate = null,
    };

    // Expected booking details
    var expectedBookingDetails = new BookingDetails
    {
        Origin = "Seattle",
        Destination = "New York",
        TravelDate = "2019-06-25",
    };

    var sut = new BookingDialog();
    var testClient = new DialogTestClient(Channels.Test, sut, initialBookingDetails);

    // Act/Assert
    var reply = await testClient.SendActivityAsync<IMessageActivity>("hi");
    ...

    var bookingResults = (BookingDetails)testClient.DialogTurnResult.Result;
    Assert.Equal(expectedBookingDetails.Origin, bookingResults?.Origin);
    Assert.Equal(expectedBookingDetails.Destination, bookingResults?.Destination);
    Assert.Equal(expectedBookingDetails.TravelDate, bookingResults?.TravelDate);
}

이 테스트를 매개 변수화하기 위해 테스트 사례 데이터가 포함된 클래스를 만들었습니다 BookingDialogTestCase . 여기에는 초기 BookingDetails 개체, 예상 BookingDetails 된 문자열 및 사용자가 보낸 발화와 각 턴에 대한 대화 상자의 예상 회신이 포함된 문자열 배열이 포함됩니다.

public class BookingDialogTestCase
{
    public BookingDetails InitialBookingDetails { get; set; }

    public string[,] UtterancesAndReplies { get; set; }

    public BookingDetails ExpectedBookingDetails { get; set; }
}

또한 테스트에서 사용할 테스트 사례 컬렉션을 반환하는 메서드를 노출 IEnumerable<object[]> BookingFlows() 하는 도우미 BookingDialogTestsDataGenerator 클래스를 만들었습니다.

각 테스트 사례를 Visual Studio 테스트 탐색기에서 별도의 항목으로 표시하려면 XUnit 테스트 실행기에서는 이를 간소화하기 위해 구현과 같은 BookingDialogTestCase 복잡한 형식이 필요합니다. Bot.Builder.Testing 프레임워크는 이 인터페이스를 구현하는 클래스를 제공하고 TestDataObject 구현IXunitSerializable하지 않고도 테스트 사례 데이터를 래핑하는 데 사용할 수 IXunitSerializable있습니다.

다음은 두 클래스가 IEnumerable<object[]> BookingFlows() 사용되는 방법을 보여 주는 조각입니다.

public static class BookingDialogTestsDataGenerator
{
    public static IEnumerable<object[]> BookingFlows()
    {
        // Create the first test case object
        var testCaseData = new BookingDialogTestCase
        {
            InitialBookingDetails = new BookingDetails(),
            UtterancesAndReplies = new[,]
            {
                { "hi", "Where would you like to travel to?" },
                { "Seattle", "Where are you traveling from?" },
                { "New York", "When would you like to travel?" },
                { "tomorrow", $"Please confirm, I have you traveling to: Seattle from: New York on: {DateTime.Now.AddDays(1):yyyy-MM-dd}. Is this correct? (1) Yes or (2) No" },
                { "yes", null },
            },
            ExpectedBookingDetails = new BookingDetails
            {
                Destination = "Seattle",
                Origin = "New York",
                TravelDate = $"{DateTime.Now.AddDays(1):yyyy-MM-dd}",
            }, 
        };
        // wrap the test case object into TestDataObject and return it.
        yield return new object[] { new TestDataObject(testCaseData) };

        // Create the second test case object
        testCaseData = new BookingDialogTestCase
        {
            InitialBookingDetails = new BookingDetails
            {
                Destination = "Seattle",
                Origin = "New York",
                TravelDate = null,
            },
            UtterancesAndReplies = new[,]
            {
                { "hi", "When would you like to travel?" },
                { "tomorrow", $"Please confirm, I have you traveling to: Seattle from: New York on: {DateTime.Now.AddDays(1):yyyy-MM-dd}. Is this correct? (1) Yes or (2) No" },
                { "yes", null },
            },
            ExpectedBookingDetails = new BookingDetails
            {
                Destination = "Seattle",
                Origin = "New York",
                TravelDate = $"{DateTime.Now.AddDays(1):yyyy-MM-dd}",
            },
        };
        // wrap the test case object into TestDataObject and return it.
        yield return new object[] { new TestDataObject(testCaseData) };
    }
}

테스트 데이터와 테스트 사례 컬렉션을 노출하는 클래스를 저장할 개체를 만들면 테스트에 데이터를 공급하는 대신 InlineData XUnit MemberData 특성을 사용합니다. 첫 번째 매개 변수 MemberData 는 테스트 사례 컬렉션을 반환하는 정적 함수의 이름이고 두 번째 매개 변수는 이 메서드를 노출하는 클래스의 형식입니다.

[Theory]
[MemberData(nameof(BookingDialogTestsDataGenerator.BookingFlows), MemberType = typeof(BookingDialogTestsDataGenerator))]
public async Task DialogFlowUseCases(TestDataObject testData)
{
    // Get the test data instance from TestDataObject
    var bookingTestData = testData.GetObject<BookingDialogTestCase>();
    var sut = new BookingDialog();
    var testClient = new DialogTestClient(Channels.Test, sut, bookingTestData.InitialBookingDetails);

    // Iterate over the utterances and replies array.
    for (var i = 0; i < bookingTestData.UtterancesAndReplies.GetLength(0); i++)
    {
        var reply = await testClient.SendActivityAsync<IMessageActivity>(bookingTestData.UtterancesAndReplies[i, 0]);
        Assert.Equal(bookingTestData.UtterancesAndReplies[i, 1], reply?.Text);
    }

    // Assert the resulting BookingDetails object
    var bookingResults = (BookingDetails)testClient.DialogTurnResult.Result;
    Assert.Equal(bookingTestData.ExpectedBookingDetails?.Origin, bookingResults?.Origin);
    Assert.Equal(bookingTestData.ExpectedBookingDetails?.Destination, bookingResults?.Destination);
    Assert.Equal(bookingTestData.ExpectedBookingDetails?.TravelDate, bookingResults?.TravelDate);
}

다음은 테스트가 실행될 때 Visual Studio 테스트 탐색기에서 테스트에 대한 DialogFlowUseCases 결과의 예입니다.

Example results for the booking dialog.

모의 개체 사용

현재 테스트되지 않은 항목에 모의 요소를 사용할 수 있습니다. 참조를 위해 이 수준은 일반적으로 단위 및 통합 테스트로 간주될 수 있습니다.

가능한 한 많은 요소를 조롱하면 테스트 중인 요소를 더 잘 격리할 수 있습니다. 모의 요소의 후보로는 스토리지, 어댑터, 미들웨어, 활동 파이프라인, 채널 및 봇에 직접 속하지 않는 모든 항목이 포함됩니다. 또한 테스트 중인 봇의 부분에 포함되지 않은 미들웨어와 같은 특정 측면을 일시적으로 제거하여 각 부분을 격리할 수도 있습니다. 그러나 미들웨어를 테스트하는 경우 봇을 모의하는 것이 좋습니다.

모의 요소는 요소를 다른 알려진 개체로 바꾸는 것부터 최소한의 hello world 기능을 구현하는 것까지 몇 가지 형태를 취할 수 있습니다. 필요하지 않은 경우 요소를 제거하거나 아무 작업도 수행하지 않도록 강제하는 형식을 사용할 수도 있습니다.

Mocks를 사용하면 데이터베이스, 언어 모델 또는 기타 개체와 같은 외부 리소스를 사용하지 않고도 대화 상자의 종속성을 구성하고 테스트를 실행하는 동안 알려진 상태인지 확인할 수 있습니다.

대화 상자를 더 쉽게 테스트하고 외부 개체에 대한 종속성을 줄이기 위해 대화 상자 생성자에 외부 종속성을 삽입해야 할 수도 있습니다.

예를 들어 다음에서 MainDialog인스턴스화하는 BookingDialog 대신

public MainDialog()
    : base(nameof(MainDialog))
{
    ...
    AddDialog(new BookingDialog());
    ...
}

다음과 같이 BookingDialog 인스턴스를 생성자 매개 변수로 전달합니다.

public MainDialog(BookingDialog bookingDialog)
    : base(nameof(MainDialog))
{
    ...
    AddDialog(bookingDialog);
    ...
}

이렇게 하면 실제 BookingDialog 클래스를 BookingDialog 호출하지 않고도 인스턴스를 모의 개체로 바꾸고 단위 테스트를 MainDialog 작성할 수 있습니다.

// Create the mock object
var mockDialog = new Mock<BookingDialog>();

// Use the mock object to instantiate MainDialog
var sut = new MainDialog(mockDialog.Object);

var testClient = new DialogTestClient(Channels.Test, sut);

모의 대화 상자

위에서 설명했듯이, MainDialogBookingDialog를 호출하여 BookingDetails 개체를 획득합니다. 다음과 같이 모의 BookingDialog 인스턴스를 구현하고 구성합니다.

// Create the mock object for BookingDialog.
var mockDialog = new Mock<BookingDialog>();
mockDialog
    .Setup(x => x.BeginDialogAsync(It.IsAny<DialogContext>(), It.IsAny<object>(), It.IsAny<CancellationToken>()))
    .Returns(async (DialogContext dialogContext, object options, CancellationToken cancellationToken) =>
    {
        // Send a generic activity so we can assert that the dialog was invoked.
        await dialogContext.Context.SendActivityAsync($"{mockDialogNameTypeName} mock invoked", cancellationToken: cancellationToken);

        // Create the BookingDetails instance we want the mock object to return.
        var expectedBookingDialogResult = new BookingDetails()
        {
            Destination = "Seattle",
            Origin = "New York",
            TravelDate = $"{DateTime.UtcNow.AddDays(1):yyyy-MM-dd}"
        };

        // Return the BookingDetails we need without executing the dialog logic.
        return await dialogContext.EndDialogAsync(expectedBookingDialogResult, cancellationToken);
    });

// Create the sut (System Under Test) using the mock booking dialog.
var sut = new MainDialog(mockDialog.Object);

이 예제에서는 Moq를 사용하여 모의 대화 상자를 만들고 SetupReturns 메서드를 사용하여 대화 상자의 동작을 구성했습니다.

LUIS 결과 모의

참고 항목

LUIS(Language Understanding)는 2025년 10월 1일에 사용 중지됩니다. 2023년 4월 1일부터 새 LUIS 리소스를 만들 수 없습니다. 이제 최신 버전의 언어 이해가 Azure AI Language의 일부로 제공됩니다.

Azure AI Language의 기능인 CLU(대화형 언어 이해)는 업데이트된 LUIS 버전입니다. Bot Framework SDK의 언어 이해 지원에 대한 자세한 내용은 자연어 이해를 참조하세요.

간단한 시나리오에서는 다음과 같이 코드를 통해 모의 LUIS 결과를 구현할 수 있습니다.

var mockRecognizer = new Mock<IRecognizer>();
mockRecognizer
    .Setup(x => x.RecognizeAsync<FlightBooking>(It.IsAny<ITurnContext>(), It.IsAny<CancellationToken>()))
    .Returns(() =>
    {
        var luisResult = new FlightBooking
        {
            Intents = new Dictionary<FlightBooking.Intent, IntentScore>
            {
                { FlightBooking.Intent.BookFlight, new IntentScore() { Score = 1 } },
            },
            Entities = new FlightBooking._Entities(),
        };
        return Task.FromResult(luisResult);
    });

LUIS 결과는 복잡할 수 있습니다. JSON 파일에서 원하는 결과를 캡처하고, 프로젝트에 리소스로 추가하고, LUIS 결과로 역직렬화하는 것이 더 간단합니다. 예를 들면 다음과 같습니다.

var mockRecognizer = new Mock<IRecognizer>();
mockRecognizer
    .Setup(x => x.RecognizeAsync<FlightBooking>(It.IsAny<ITurnContext>(), It.IsAny<CancellationToken>()))
    .Returns(() =>
    {
        // Deserialize the LUIS result from embedded json file in the TestData folder.
        var bookingResult = GetEmbeddedTestData($"{GetType().Namespace}.TestData.FlightToMadrid.json");

        // Return the deserialized LUIS result.
        return Task.FromResult(bookingResult);
    });

추가 정보