【问题标题】:Test a dialog that needs to be forwarded to测试需要转发到的对话框
【发布时间】:2018-03-22 03:18:16
【问题描述】:

我创建了一个希望转发到的对话框

using Microsoft.Bot.Builder.Dialogs;
using pc.apm.bot.Services;
using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace pc.apm.bot.Dialogs
{
    [Serializable]
    public class NewUserDialog : IDialog<string>
    {
        IApmService _apmService;
        LangaugeCodes _langaugeCode;

        public NewUserDialog(IApmService apmService, LangaugeCodes langaugeCode)
        {
            _apmService = apmService;
            _langaugeCode = langaugeCode;
        }

        public async Task StartAsync(IDialogContext context)
        {
            if (new TraceSwitch("apmDiagnostics", "").Level == TraceLevel.Info)
                await context.PostAsync($"Current Dialog: {this.GetType().Name}");

            context.Wait<string>(MessageReceivedAsync);
        }

        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<string> result)
        {
            var userEmail = await result;

            await context.PostAsync(StringResourceService.GetStringResource(StringKeys.NewUserStarted_Key, _langaugeCode));

            var apmId = await _apmService.CreateUserAsync(userEmail.ToLower());

            var UserProvisionedAlfabet_Text = StringResourceService.GetStringResource(StringKeys.UserProvisionedAlfabet_Key, _langaugeCode);
            await context.PostAsync(String.Format(UserProvisionedAlfabet_Text, userEmail));

            context.Done(apmId);
        }
    }
}

现在它的工作方式是在上一个对话框中,我有一些逻辑决定需要配置新用户,在这种情况下,它会将用户电子邮件转发到 NewUserDialog 以执行此操作。

await context.Forward(
    child: new NewUserDialog(), 
    resume: (c, r) => AddProfile(context, result), 
    item: user.Email,
    token: CancellationToken.None);

所以一切正常,花花公子,我遇到的问题是对这段代码进行单元测试;我正在尝试遵循 bot builder 测试项目中的规定

https://github.com/Microsoft/BotBuilder/tree/master/CSharp/Tests/Microsoft.Bot.Sample.Tests

现在我的测试开始了,只是当我的 NewUserDialog 尝试等待电子邮件地址时,事情失败并引发异常

pc.apm.bot.tests.Test_New_User_Dialog.Create_New_User 抛出异常: Microsoft.Bot.Builder.Internals.Fibers.InvalidTypeException:无效类型:预期 System.String,有 Activity

所以我看到这是一个类型问题;但我不知道如何通过测试代码将电子邮件地址传递给对话框。

这是我的测试代码

using Autofac;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs.Internals;
using Microsoft.Bot.Builder.Tests;
using Microsoft.Bot.Connector;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using pc.apm.bot.Dialogs;
using pc.apm.bot.Services;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace pc.apm.bot.tests
{
    [TestClass]
    public class Test_New_User_Dialog : DialogTestBase
    {
        [TestMethod]
        public async Task Test_method() => Assert.IsTrue(await Task.FromResult(true));

        [TestMethod]
        public async Task Create_New_User()
        {
            var mockApmService = new Mock<IApmService>(MockBehavior.Strict);
            mockApmService
                .Setup(m => m.CreateUserAsync(It.IsAny<string>()))
                .Returns<string>(x => Task.FromResult("123-123"));

            var NewUserDialog = new NewUserDialog(mockApmService.Object, LangaugeCodes.en_US);

            var toBot = DialogTestBase.MakeTestMessage();
            toBot.From.Id = Guid.NewGuid().ToString();

            Func<IDialog<string>> MakeRoot = () => NewUserDialog;

            using (new FiberTestBase.ResolveMoqAssembly(NewUserDialog))
            using (var container = Build(Options.MockConnectorFactory | Options.ScopedQueue, NewUserDialog))
            {
                using (var scope = DialogModule.BeginLifetimeScope(container, toBot))
                {
                    DialogModule_MakeRoot.Register(scope, MakeRoot);
                    await Conversation.SendAsync(scope, toBot);

                    var firstResponse = scope.Resolve<Queue<IMessageActivity>>().Dequeue();
                    Assert.IsTrue(firstResponse.Text.Equals("Looks as if you are a new user, let's get you started!"));

                    var secondResponse = scope.Resolve<Queue<IMessageActivity>>().Dequeue();
                    Assert.IsTrue(secondResponse.Text.Equals("A user for pawel.chooch@fake.com has been provisioned in System"));
                }

            }
        }
    }
}

所以简而言之,我的问题是如何通过将参数从父对话框转发给它来测试接收参数的对话框?

【问题讨论】:

    标签: c# unit-testing botframework


    【解决方案1】:

    好的,经过大量的努力,我终于得到了它,

    using Autofac;
    using Microsoft.Bot.Builder.Dialogs;
    using Microsoft.Bot.Builder.Dialogs.Internals;
    using Microsoft.Bot.Builder.Tests;
    using Microsoft.Bot.Connector;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    using pc.apm.bot.Dialogs;
    using pc.apm.bot.Services;
    using pc.apm.bot.tests.Interfaces;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace pc.apm.bot.tests
    {
        [TestClass]
        public class Test_New_User_Dialog : DialogTestBase
        {
            [TestMethod]
            public async Task Test_method() => Assert.IsTrue(await Task.FromResult(true));
    
            [TestMethod]
            public async Task Create_New_user_Dialog()
            {
                var mockRootDialog = new Mock<IMessageRecievedDialog<IMessageActivity>>(MockBehavior.Loose);
                var mockApmService = new Mock<IApmService>(MockBehavior.Strict);
    
                mockApmService.Setup(m => m.CreateUserAsync(It.IsAny<string>()))
                              .Returns<string>(x => Task.FromResult("123-123"));
    
                var NewUserDialog = new NewUserDialog(mockApmService.Object, LangaugeCodes.en_US);
                var userEmail = "pawel.chooch@fake.com";
    
                mockRootDialog.Setup(d => d.StartAsync(It.IsAny<IDialogContext>()))
                              .Returns<IDialogContext>(
                                    context =>
                                    {
                                        context.Wait(mockRootDialog.Object.MessageRecievedAsync);
                                        return Task.CompletedTask;
                                    });
    
                mockRootDialog.Setup(d => d.MessageRecievedAsync(It.IsAny<IDialogContext>(), It.IsAny<IAwaitable<IMessageActivity>>()))
                              .Returns<IDialogContext, IAwaitable<IMessageActivity>>(async (context, message) =>
                              {
                                  var email = await message;
                                  await context.Forward(
                                      child: NewUserDialog,
                                      resume: async (c, r) =>
                                      {
                                          Assert.AreEqual("123-123", await r);
                                          c.Done<object>(null);
                                      },
                                      item: email.Text,
                                      token: CancellationToken.None);
                              });
    
                var toBot = DialogTestBase.MakeTestMessage();
    
                using (new FiberTestBase.ResolveMoqAssembly(mockRootDialog.Object, NewUserDialog))
                using (var container = Build(Options.MockConnectorFactory | Options.ScopedQueue, mockRootDialog.Object, NewUserDialog))
                using (var scope = DialogModule.BeginLifetimeScope(container, toBot))
                {
                    DialogModule_MakeRoot.Register(scope, () => mockRootDialog.Object);
    
                    var task = scope.Resolve<IPostToBot>();
                    toBot.Text = userEmail;
                    await task.PostAsync(toBot, CancellationToken.None);
    
                    var firstResponse = scope.Resolve<Queue<IMessageActivity>>().Dequeue();
                    Assert.IsTrue(firstResponse.Text.Equals("Looks as if you are a new user, let's get you started!"));
    
                    var secondResponse = scope.Resolve<Queue<IMessageActivity>>().Dequeue();
                    Assert.IsTrue(secondResponse.Text.Equals($"A user for {userEmail} has been provisioned in ALFABET"));
                }
            }
        }
    }
    

    现在除了我的 apm 服务,我创建了一个接口 IMessageRecievedDialog

    using Microsoft.Bot.Builder.Dialogs;
    using System.Threading.Tasks;
    
    namespace pc.apm.bot.tests.Interfaces
    {
        public  interface IMessageRecievedDialog<T> : IDialog<T>
        {
            Task MessageRecievedAsync(IDialogContext context, IAwaitable<T> result);
        }
    }
    

    这实际上不是必需的,因为在 Microsoft.Bot.Builder.Tests 命名空间中有一个接口“IDialogFrames”,它是完全相同的东西。我再次从 Microsoft.bot.builder.tests 中从 DialogTask_Forward 测试中汲取了解决方案的灵感

    [TestMethod]
    public async Task DialogTask_Forward()
    {
        var dialogOne = new Mock<IDialogFrames<string>>(MockBehavior.Loose);
        var dialogTwo = new Mock<IDialogFrames<string>>(MockBehavior.Loose);
        const string testMessage = "foo";
    
        dialogOne
            .Setup(d => d.StartAsync(It.IsAny<IDialogContext>()))
            .Returns<IDialogContext>(async context => { context.Wait(dialogOne.Object.ItemReceived); });
    
        dialogOne
            .Setup(d => d.ItemReceived(It.IsAny<IDialogContext>(), It.IsAny<IAwaitable<IMessageActivity>>()))
            .Returns<IDialogContext, IAwaitable<IMessageActivity>>(async (context, message) =>
            {
                var msg = await message;
                await context.Forward(dialogTwo.Object, dialogOne.Object.ItemReceived<string>, msg, CancellationToken.None);
            });
    
        dialogOne
            .Setup(d => d.ItemReceived(It.IsAny<IDialogContext>(), It.IsAny<IAwaitable<string>>()))
            .Returns<IDialogContext, IAwaitable<string>>(async (context, message) =>
            {
                var msg = await message;
                Assert.AreEqual(testMessage, msg);
                context.Wait(dialogOne.Object.ItemReceived);
            });
    
    
        dialogTwo
            .Setup(d => d.StartAsync(It.IsAny<IDialogContext>()))
            .Returns<IDialogContext>(async context => { context.Wait(dialogTwo.Object.ItemReceived); });
    
        dialogTwo
            .Setup(d => d.ItemReceived(It.IsAny<IDialogContext>(), It.IsAny<IAwaitable<IMessageActivity>>()))
            .Returns<IDialogContext, IAwaitable<IMessageActivity>>(async (context, message) =>
            {
                var msg = await message;
                context.Done(msg.Text);
            });
    
        Func<IDialog<object>> MakeRoot = () => dialogOne.Object;
        var toBot = MakeTestMessage();
    
        using (new FiberTestBase.ResolveMoqAssembly(dialogOne.Object, dialogTwo.Object))
        using (var container = Build(Options.None, dialogOne.Object, dialogTwo.Object))
        {
            using (var scope = DialogModule.BeginLifetimeScope(container, toBot))
            {
                DialogModule_MakeRoot.Register(scope, MakeRoot);
                var task = scope.Resolve<IPostToBot>();
                toBot.Text = testMessage;
                await task.PostAsync(toBot, CancellationToken.None);
    
                dialogOne.Verify(d => d.StartAsync(It.IsAny<IDialogContext>()), Times.Once);
                dialogOne.Verify(d => d.ItemReceived(It.IsAny<IDialogContext>(), It.IsAny<IAwaitable<IMessageActivity>>()), Times.Once);
                dialogOne.Verify(d => d.ItemReceived(It.IsAny<IDialogContext>(), It.IsAny<IAwaitable<string>>()), Times.Once);
    
                dialogTwo.Verify(d => d.StartAsync(It.IsAny<IDialogContext>()), Times.Once);
                dialogTwo.Verify(d => d.ItemReceived(It.IsAny<IDialogContext>(), It.IsAny<IAwaitable<IMessageActivity>>()), Times.Once);
            }
        }
    }
    

    以下链接确实有帮助 https://channel9.msdn.com/Series/DevOps-for-the-Bot-Framework/Testing-the-Bot-Framework?term=bot

    我对特定于 botframework 的代码仍然不够熟悉,无法真正提供解释,因此我认为这是理所当然的。无论如何,我希望我的腿部工作能帮助别人。干杯。

    【讨论】:

    • 如果有人可以扩展我的答案或提供更好的答案,请随时分享。我的解决方案充其量是不稳定的。
    猜你喜欢
    • 1970-01-01
    • 2012-02-15
    • 2011-08-12
    • 1970-01-01
    • 2013-06-30
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 2021-09-14
    相关资源
    最近更新 更多