如何对需要用户 select 在 Bot Framework 中进行选择的自定义提示进行单元测试

How to unit test custom prompt that requires user select a choice in Bot Framework

我有一些使用自适应卡片制作的自定义提示,需要用户输入 input.ChoiceSet 和 input.Text。

我的问题是,如果我有一张有 3 个选择的卡片('Red'、'Blue'、'Green'),我想测试“红色”的结果select编辑。如何发送选择并在我的测试代码中获得结果。 我想在 selected 并且用户点击提交按钮后对结果和流程进行单元测试。

我使用 JObject 获取用户的 selection 作为字符串;

在我的对话框的构造函数中 class 我已将提示添加到对话框中。

AddDialog(new CustomPrompt("cardPrompt", DialogValidators.AdaptiveCardValidatorAsync));

这是我用于测试的对话代码。

private async Task<DialogTurnResult> aStep(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
            var adaptiveActivity = stepContext.Context.Activity.CreateReply();
            adaptiveActivity.AddCardAttachment();
            return await stepContext.PromptAsync(
                "CardPrompt",
                new PromptOptions
                {
                    Prompt = adaptiveActivity,
                    RetryPrompt = MessageFactory.Text("xxx"),
                    Validations = new List<string> { "selectionCard" }
                });
}

private async Task<DialogTurnResult> bStep(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
            JObject answerObject = (JObject)JsonConvert.DeserializeObject(stepContext.Result.ToString());
            string userChoice = answerObject["choiceID"].ToString();
}

下面是我的测试代码。

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>("Red");
Assert.AreEqual(XXXX, reply....);

如何使用 DialogTestClient 进行测试?

感谢您为此付出宝贵的时间。

更新

下面是我的提示class。它扩展了具有抽象方法(OnPromptAsync 和 OnRecognizeAsync)的 Prompt2 并扩展了 Dialog class.


public class CustomPrompt : Prompt2<string>
    {
        public CustomPrompt(string dialogId, PromptValidator<string> validator = null)
            : base(dialogId, validator)
        {
        }

        protected async override Task OnPromptAsync(ITurnContext turnContext, IDictionary<string, object> state, PromptOptions options, bool isRetry, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            if (isRetry && options.RetryPrompt != null)
            {
                await turnContext.SendActivityAsync(options.RetryPrompt, cancellationToken).ConfigureAwait(false);
            }
            else if (options.Prompt != null)
            {
                await turnContext.SendActivityAsync(options.Prompt, cancellationToken).ConfigureAwait(false);
            }
        }

        protected override Task<PromptRecognizerResult<string>> OnRecognizeAsync(ITurnContext turnContext, IDictionary<string, object> state, PromptOptions options, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (turnContext == null)
            {
                throw new ArgumentNullException(nameof(turnContext));
            }

            var result = new PromptRecognizerResult<string>();
            if (turnContext.Activity.Type == ActivityTypes.Message)
            {
                var message = turnContext.Activity.AsMessageActivity();
                if (!string.IsNullOrEmpty(message.Text))
                {
                    result.Succeeded = true;
                    result.Value = message.Text;
                }

                /*Add handling for Value from adaptive card*/
                else if (message.Value != null)
                {
                    result.Succeeded = true;
                    result.Value = message.Value.ToString();
                }
            }

            return Task.FromResult(result);
        }
    }


这是我的卡片结构。

{
  "type": "AdaptiveCard",
  "body": [
    {
      "type": "Container",
      "items": [
        {
          "type": "Input.ChoiceSet",
          "wrap":  true,
          "id": "choiceID",
          "value": {defaultValue}
          "placeholder": "Placeholder text",
          "choices": [
            {
              title: "aaaa",
              value: "testChoice"
            }
          ],
          "style": "expanded"
        }
      ]
    }
  ],
  "actions": [
    {
      "type": "Action.Submit",
      "id": "submit",
      "title": "Confirm",
      "data": {
        "value": "submit",
        "id": selectionCard"
      }
    },
    {
      "type": "Action.Submit",
      "id": "cancel",
      "title": "Cancel",
      "data": {
        "value": "cancel",
        "id": "selectionCard"
      }
    }
  ],
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.1"

我想知道如何测试我是否 select 使用 TestFlow 选择任何卡片并从机器人那里获得正确的响应。 谢谢。

提示 class 中的代码显示自适应卡片提交操作数据已传输到 activity 值 属性:

中的机器人
/*Add handling for Value from adaptive card*/
else if (message.Value != null)
{
    result.Succeeded = true;
    result.Value = message.Value.ToString();
}

您在测试中必须做的就是通过自己填充其值 属性 来模拟发送这样一个 activity。

var activity = new Activity(ActivityTypes.Message, value: submitActionData);
reply = await testClient.SendActivityAsync<IMessageActivity>(activity);

这应该适用于对话测试客户端或测试流程。你可以在我的 cards library tests.

中看到一些这样的例子