如何在没有对话框的情况下对我的机器人进行单元测试?(C#) [英] How can i unit test my bot without dialogs? (c#)

查看:60
本文介绍了如何在没有对话框的情况下对我的机器人进行单元测试?(C#)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在Microsoft Bot Framework 4中从事自动化单元测试.从那里,我想检查来自机器人的简单对话语句.在CoreBot中测试示例( https://docs.microsoft.com/zh-cn/azure/bot-service/unit-test-bots?view=azure-bot-service-4.0&tabs=csharp )演示了如何做到这一点,但对我来说,我的机器人并没有使用对话框(据我所知).

i am currently working on automated unit tests inside the Microsoft Bot Framework 4. From there, i want to check simple conversational statements from the bot. In the CoreBot Tests sample (https://docs.microsoft.com/en-us/azure/bot-service/unit-test-bots?view=azure-bot-service-4.0&tabs=csharp) is demonstrated how it is possible to do that but for me, my bot isnt using dialogs (as far as i know).

我现在的问题是,我如何才能对简单的问题/答案陈述进行单元测试?我的主要目标是对我的QnA Maker知识库进行单元测试.

My question here is now, how can i unit test simple Question/Answer Statements? My main goal is to unit test my QnA Maker Knowledge Bases.

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Logging;
using System;
using Newtonsoft.Json;
using System.IO;
using Microsoft.Bot.Builder.AI.QnA;

using Microsoft.Extensions.Configuration;

namespace SEKAI.Bots
{
    public class DispatchBot : ActivityHandler
    {
        private ILogger<DispatchBot> _logger;
        private IBotServices _botServices;
        private IConfiguration _configuration;

        public DispatchBot(IConfiguration configuration, IBotServices botServices, ILogger<DispatchBot> logger)
        {
            _configuration = configuration;
            _logger = logger;
            _botServices = botServices;
        }

        protected async Task NoMatchFound(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            var table = BotUtility.BotUtility.GetTableReference(_configuration);
            BotUtility.BotUtility.InsertRecord(turnContext, table);

            // Wird ausgeführt, wenn keine KnowledgeBase gefunden wird
            System.Diagnostics.Debug.WriteLine("### FINDE KEINE PASSENDE ANTWORT ###");
            await turnContext.SendActivityAsync(MessageFactory.Text("Leider kann ich Ihnen hierbei noch nicht weiterhelfen. Ich bin aber schon dabei, Neues zu lernen!"), cancellationToken);
        }

        // Wenn der Benutzer den Chat startet
        protected override async Task OnEventActivityAsync(ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken)
        {
            if (turnContext.Activity.Name == "webchat/join")
            {
                string WelcomeCardpath = Path.Combine(".", "AdaptiveCards", "WelcomeCard.json");
                var cardAttachment = BotUtility.BotUtility.CreateAdaptiveCard(WelcomeCardpath);
                await turnContext.SendActivityAsync(MessageFactory.Attachment(cardAttachment), cancellationToken);
            }
        }

        // Wenn ein Nutzer eine Nachricht schreibt
        protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            // First, we use the dispatch model to determine which cognitive service (LUIS or QnA) to use.
            var recognizerResult = await _botServices.Dispatch.RecognizeAsync(turnContext, cancellationToken);

            // Top intent tell us which cognitive service to use.
            var topIntent = recognizerResult.GetTopScoringIntent();

            // Next, we call the dispatcher with the top intent.
            await DispatchToTopIntentAsync(turnContext, topIntent.intent, recognizerResult, cancellationToken);
        }

        // Suche nach der richtigen KnowledgeBase
        private async Task DispatchToTopIntentAsync(ITurnContext<IMessageActivity> turnContext, string intent, RecognizerResult recognizerResult, CancellationToken cancellationToken)
        {
            switch (intent)
            {
                case "q_SEKAI_Chitchat":
                    await ProcessSEKAI_ChitchatAsync(turnContext, cancellationToken);
                    break;

                default:
                    // Wird ausgeführt, wenn keine KnowledgeBase gefunden wird
                    _logger.LogInformation($"Dispatch unrecognized intent: {intent}.");
                    await NoMatchFound(turnContext, cancellationToken);
                    break;
            }
        }

        // Bearbeitung aus SEKAI_Chitchat
        private async Task ProcessSEKAI_ChitchatAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            _logger.LogInformation("ProcessSEKAI_ChitchatAsync");

            // Confidence Score zur KnowledgeBase
            var metadata = new Metadata();
            var qnaOptions = new QnAMakerOptions();
            qnaOptions.ScoreThreshold = 0.70F;

            // Speichere die Antwort aus der KnowledgeBase
            var results = await _botServices.SEKAI_Chitchat.GetAnswersAsync(turnContext, qnaOptions);
            if (results.Any())
            {
                // Speichere die Antwort aus der KnowledgeBase für die Schlüsselwort-Verarbeitung
                string savetext = results.First().Answer;
                System.Diagnostics.Debug.WriteLine(savetext);

                if (savetext.Contains("{card}"))
                {
                    // Hier wird das Schlüsselwort für die Antwortausgabe entfernt
                    int firstKeyword = savetext.IndexOf("{card}") + "{card}".Length;
                    int lastKeyword = savetext.LastIndexOf("{/card}");
                    string subsavetext = savetext.Substring(firstKeyword, lastKeyword - firstKeyword);
                    System.Diagnostics.Debug.WriteLine(subsavetext);

                    // Ausgabe der Adaptive Card
                    savetext = savetext.Replace("{card}" + subsavetext + "{/card}", "");
                    string AdaptiveCardPath = Path.Combine(".", "AdaptiveCards", subsavetext + ".json");
                    var cardAttachment = BotUtility.BotUtility.CreateAdaptiveCard(AdaptiveCardPath);
                    await turnContext.SendActivityAsync(MessageFactory.Attachment(cardAttachment), cancellationToken);

                    // Ausgabe von Text
                    await turnContext.SendActivityAsync(MessageFactory.Text(savetext), cancellationToken);
                }
                else
                {
                    // Befindet sich in der Datenbank kein Schlüsselwort, wird nur die Antwort ausgegeben
                    await turnContext.SendActivityAsync(MessageFactory.Text(savetext), cancellationToken);
                }
            }
            else
            {
                // Wird ausgegeben, wenn keine Antwort in der KnowledgeBase passt
                await NoMatchFound(turnContext, cancellationToken);
            }
        }
    }
}

我构建的机器人完全基于带有Dispatch示例的NLP(

The bot i have build is based completly on the NLP with Dispatch sample (https://github.com/microsoft/BotBuilder-Samples/tree/main/samples/csharp_dotnetcore/14.nlp-with-dispatch).

我已经对机器人进行了一些修改,这就是为什么我为我的版本添加了主文件(GitHub存储库中的Dispatchbot.cs文件).

I have already modified the bot a bit and thats why i added the main file (Dispatchbot.cs file in the GitHub repo) for my version.

推荐答案

我无法帮助您使用C#的语法,但是我的nodejs bot中有一些不是对话框的测试,这可能会对您有所帮助.本质上,您只需创建一个TestAdapter并将其与活动一起传递给您的机器人.例如,这是我的dispatchBot.test.js文件的一部分:

I can't help you with the syntax for C#, but I have some tests in my nodejs bot that are not dialogs and this may help you. Essentially, you just create a TestAdapter and pass that with an activity to your bot. For example, here is part of my dispatchBot.test.js file:

const { TestAdapter, ActivityTypes, TurnContext, ConversationState, MemoryStorage, UserState } = require('botbuilder');
const { DispatchBot } = require('../../bots/dispatchBot');
const assert = require('assert');
const nock = require('nock');
require('dotenv').config({ path: './.env' });

// Tests using mocha framework
describe('Dispatch Bot Tests', () => {

    const testAdapter = new TestAdapter();
    async function processActivity(activity, bot) {
        const context = new TurnContext(testAdapter, activity);
        await bot.run(context);
    }

    it('QnA Generic Response'), async () => {
        const memoryStorage = new MemoryStorage();
        let bot = new DispatchBot(new ConversationState(memoryStorage), new UserState(memoryStorage), appInsightsClient);

        // Create message activity
        const messageActivity = {
            type: ActivityTypes.Message,
            channelId: 'test',
            conversation: {
                id: 'someId'
            },
            from: { id: 'theUser' },
            recipient: { id: 'theBot' },
            text: `This is an unrecognized QnA utterance for testing`
        };

        // Send the conversation update activity to the bot.
        await processActivity(messageActivity, bot);

        // Assert we got the right response
        let reply = testAdapter.activityBuffer.shift();
        assert.equal(reply.text,defaultQnaResponse);
    });
});

如果您的漫游器以多种活动响应,则即使只是清除缓冲区,您也只需继续使用 testAdapter.activityBuffer.shift().否则,它将那些消息保留在缓冲区中以供后续测试.希望这会有所帮助!

If your bot responds with multiple activities, you just need to continue to use testAdapter.activityBuffer.shift(), even if just to clear the buffer. Otherwise it would keep those messages in the buffer for subsequent tests. Hopefully this will help!

这篇关于如何在没有对话框的情况下对我的机器人进行单元测试?(C#)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆