测试需要转发到的对话框

时间:2017-10-10 16:18:49

标签: c# unit-testing botframework

我已经创建了一个期望转发到

的对话框
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);

所以一切正常,花花公子,我遇到的问题是单元测试这段代码;我试图遵循机器人制造商测试项目中的内容

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:invalid type:expected System.String,have 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"));
                }

            }
        }
    }
}

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

1 个答案:

答案 0 :(得分:0)

好的,经过大量的努力,我终于明白了,

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特定的代码来真正提供解释,因此我认为它是理所当然的。无论如何,我希望我的腿部工作可以帮助别人。欢呼声。