如何在 Bot Framework 的测试函数中访问用户和对话数据

Posted

技术标签:

【中文标题】如何在 Bot Framework 的测试函数中访问用户和对话数据【英文标题】:How to Access User & Conversation Data in Test Functions for Bot Framework 【发布时间】:2020-03-09 11:45:19 【问题描述】:

我需要在运行单元测试时访问用户和对话数据。

在我的机器人代码中,我在MS documentation 之后实现了用户和对话数据。

在为我的对话框运行单元测试时,我无法访问我在测试期间更新的保存用户数据。

下面是我的机器人测试代码设置(来自虚拟助手模板BotTestBase.cs)。

var storage = new MemoryStorage();
Services.AddSingleton(new UserState(storage));
Services.AddSingleton(new ConversationState(storage));
Services.AddSingleton(sp =>

    var userState = sp.GetService<UserState>();
    var conversationState = sp.GetService<ConversationState>();
    return new BotStateSet(userState, conversationState);
);

这是我的测试函数:

userState = new UserState(new MemoryStorage());
var subDialog = new SubDialog(userState);
var MainDialog = new MainDialog(subDialog);
var testClient = new DialogTestClient(Channels.Msteams, MainDialog);

// some code here

reply = await testClient.SendActivityAsync<IMessageActivity>("Yes");
Assert.AreEqual("XXXX", ((HeroCard)reply.Attachments[0].Content).Text);

reply = await testClient.SendActivityAsync<IMessageActivity>("No");
Assert.AreEqual("OOOO", ((HeroCard)reply.Attachments[0].Content).Text);

reply = await testClient.SendActivityAsync<IMessageActivity>("Checkout");
Assert.AreEqual("XOXO", ((HeroCard)reply.Attachments[0].Content).Text);

下面是我在 subDialog 中的用户数据。我可以通过userProfile.xxxx = oooo更新数据:

var userStateProfileAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
var userProfile = await userStateProfileAccessors.GetAsync(dc.Context, () => new UserProfile());

发送Yes后对话框进入子对话框,发送No后用户数据更新。

在我发送Checkout 之后,将访问用户数据以确定下一步。但是好像用户数据没有更新,我发现里面的所有属性都为空。

有人知道如何在 bot 框架中访问用户数据以进行单元测试吗?

更新

我创建了 MRE。我通过制作一个虚拟助手模板来做到这一点,然后我创建了一个对话框 CheckoutDialog.cs,它为我的 userProfile.DiscountStatus 分配一个值,并在下一步中检查它。我为此对话框 CheckoutTests.cs 创建了一个测试,当我调试测试时,我可以看到我的 userProfile.DiscountStatus 不会在步骤之间保持其状态。 Here 是 git 仓库。

【问题讨论】:

如果你能分享minimal reproducible example,那就太棒了。目前没有足够的信息来重现这里的问题。 由于缺乏足够的信息来直接提供适当的帮助,我建议的最好方法是查看这里的文档How to unit test bots 我正在研究最小的可重现示例。稍后分享,谢谢。 这能回答你的问题吗? ***.com/a/43244859/12217161 @MasLoo 它不起作用。我猜 DialogtestBase 与 V3 一起使用。我的机器人是用 V4 开发的。 【参考方案1】:

尝试在var testClient = new DialogTestClient(Channels.Msteams, MainDialog);上方添加以下行

AutoSaveStateMiddleware autoSaveStateMiddleware = new AutoSaveStateMiddleware(userState);

然后将该行更改为:

var testClient = new DialogTestClient(Channels.Msteams, MainDialog, middlewares: new List<IMiddleware>()  autoSaveStateMiddleware );

我创建了一个包含 2 个项目和 3 个类的简单存储库来测试这一点: Repo with unit test of a dialog which saves & retrieves user state between 2 turns

查看DialogTestClient.cs from Microsoft.Bot.Builder.Testing中的DialogTestClient.cs(第39行)代码,客户端仅在ConversationState上实现AutoSaveStateMiddleware。

        public DialogTestClient(string channelId, Dialog targetDialog, object initialDialogOptions = null, IEnumerable<IMiddleware> middlewares = null, ConversationState conversationState = null)
    
        ConversationState = conversationState ?? new ConversationState(new MemoryStorage());
        _testAdapter = new TestAdapter(channelId)
            .Use(new AutoSaveStateMiddleware(ConversationState));

        AddUserMiddlewares(middlewares);

        var dialogState = ConversationState.CreateProperty<DialogState>("DialogState");

        _callback = GetDefaultCallback(targetDialog, initialDialogOptions, dialogState);
    

在您的情况下,您只运行对话框。根据我所见,将状态在线保存到存储提供程序通常是在 Bot.OnTurnAsync 方法中完成的。在这种情况下,您没有机器人。使用提供的 IMiddleware 参数在 UserState 上添加 AutoSaveStateMiddleware 将导致 UserState 保存。然后您应该能够在以后的回合中读取您保存的内容。

【讨论】:

您好,感谢您的回答。这个对我有用。只是有另一个问题,我正在使用“UserProfile”,就像你在回购中所做的那样。 var userStateAccessors = _userState.CreateProperty(nameof(UserProfile)); var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());如何在 DialogTestClient 中对其进行测试或设置? 我不确定我是否完全理解您的问题。听起来您在问如何在您的情况下应用 AutoSaveStateMiddleware。在您的仓库github.com/RayGunBJ4/botFrameWorkUnitTest 中,您似乎在询问“CheckoutTests.cs”中的测试。添加: AutoSaveStateMiddleware autoSaveStateMiddleware = new AutoSaveStateMiddleware(userState);在实例化 DialogTestClient 之前,然后实例化 DialogTestClient,如: var testClient = new DialogTestClient(Channels.Msteams, checkoutDialog, middlewares: new List() autoSaveStateMiddleware );. 你需要调整你的测试。您在哪里: Assert.AreEqual("此时您没有折扣。", ((HeroCard)reply.Attachments[0].Content).Text);.结果实际上不是英雄卡。因此,更改该行,加上另一个测试中的行,使其更像:Assert.AreEqual("您将很快收到一张优惠券。",reply.Text);。这 2 个更改应该会导致您的测试通过。这意味着 userProfile.DiscountStatus 的值将根据用户对以下内容的响应设置为 true / false:“您是否拥有我们的会员资格?” 我的问题是在我的测试中应用 AutoSaveStateMiddleware 后我想获取“UserProfile”的数据。设置 AutoSaveStateMiddleware 很好。但是当我的 userProfile 在这个 var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile()) 之后基本上什么都没有时,所以我想知道是否有办法在启动 AutoSaveStateMiddleware 或 userState 时设置 userProfile?欣赏。

以上是关于如何在 Bot Framework 的测试函数中访问用户和对话数据的主要内容,如果未能解决你的问题,请参考以下文章

使用 AWS 部署 MS Bot Framework

Bot Framework:如何退出对话?

Microsoft Bot Framework - 如何将数据从 Azure 数据库获取到我的 Bot 项目?

如何在 Bot Framework C# 中使用 Bing Speech API

如何获取从 Bot Framework Composer 发送的消息的 ResourceResponse.Id

如何在 node.js 版本的 Microsoft Bot Framework 中“退出”?