Warm tip: This article is reproduced from serverfault.com, please click

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

(c# - How to unit test custom prompt that requires user select a choice in Bot Framework)

发布于 2020-12-04 22:37:21

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

我的问题是,如果我有3种选择的牌(“红色”,“蓝色”,“绿色”),并且我想测试选择“红色”的结果。如何在我的测试代码中发送选择并获得结果。在选择了某些内容并且用户点击了“提交”按钮之后,我想对结果和流程进行单元测试。

我使用JObject以字符串形式获取用户的选择。

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

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进行测试?

感谢你的时间。

更新

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


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"

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

Questioner
RayGun
Viewed
0
Kyle Delaney 2020-12-25 08:53:38

提示类中的代码显示,活动活动的value属性中,Adaptive Card提交操作数据已传输到机器人:

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

在测试中,你要做的就是通过自己填充其value属性来模拟发送此类活动。

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

这应该与对话框测试客户端或测试流程一起使用。你可以在我的卡库测试中看到一些示例