在运行单元测试时,我需要访问用户和会话数据。
在我的机器人代码中,我已经按照MS documentation实施了用户和会话数据。
在为对话框运行单元测试时,我无法访问在测试期间更新的保存用户数据。
以下是我针对机器人测试代码的设置(来自Virtual Assistant模板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仓库。
答案 0 :(得分: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 保存。然后,您应该能够阅读您在以后的回合中保存的内容。