Bot FrameworkとDirectLineを使った連携テスト(1)

· 2分で読める

会社に入社してから短期間で、Bot Framework の結合テストを担当することになりました。

グループでの私の仕事は、ボットを可能な限り安定させることですが、まず、ボット フレームワークとは何でしょうか?

インテリジェントなボットを構築、接続、展開、管理して、Web サイト、アプリ、Cortana、Microsoft Teams、Skype、Slack、Facebook Messenger などでユーザーと自然に対話します。使用した分だけ料金を支払うだけで、完全なボット構築環境をすぐに始められます。

Bot Framework の詳細については、ここ をご覧ください。

次の説明では、Bot Framework の動作に関する基本情報がすべて網羅されているわけではありません。理解できない場合は、公式ドキュメントを確認してください。

なぜ統合テストが必要なのでしょうか?

統合テストが必要なのは、同僚が修正、新機能、さらには新しいバグをプッシュするたびに、コードを運用環境にプッシュする前にこのテストが実行され、テストのいずれかが失敗した場合、コードは運用環境に移行しないためです。つまり、エンド ユーザーにはバグが発生しません。

ボットでの統合テスト?

ボットでは、統合テストが非常に重要であると私は信じています。一部のメニューが機能しない、または一部の機能が何も返さないボットは使用できません。

企業が顧客のためにボットを使用しているのは、人々に自分たちの問題で忙しくしてほしくないからです。ボットがユーザーを助けることができれば、他の従業員は自分の時間をより重要なことに費やすことができるでしょう。

ソリューションの概要。

これを機能させるために、Visual Studio でテスト プロジェクトを使用しました。このプロジェクトでは、API レストに WebClient を使用し、ケースを保存する Json ファイルを使用します。

JSON ファイル

{
  "secret": "direct-line-secret",
  "directlineGenerateTokenEndpoint": "https://directline.botframework.com/v3/directline/tokens/generate",
  "directlineConversationEndpoint": "https://directline.botframework.com/v3/directline/conversations/",
  "entries": [
    {
      "name": "DecirHola",
      "request": {
        "type": "message",
        "text": "Hola",
        "from": {
          "id": "default-user",
          "name": "User"
        },
        "locale": "es",
        "textFormat": "plain",
        "timestamp": "2018-04-09T08:04:37.195Z",
        "channelData": {
          "clientActivityId": "1523261059363.6264723268323733.0"
        },
        "entities": [
          {
            "type": "ClientCapabilities",
            "requiresBotState": true,
            "supportsTts": true,
            "supportsListening": true
          }
        ],
        "id": "61hacck8j6jg"
      },
      "response": {
        "type": "message",
        "timestamp": "2018-04-09T08:04:37.901Z",
        "localTimestamp": "2018-04-09T09:04:37+01:00",
        "serviceUrl": "http://localhost:50629",
        "channelId": "emulator",
        "from": {
          "id": "j98bbdf097a",
          "name": "Bot"
        },
        "conversation": {
          "id": "eabcie4be8ak"
        },
        "recipient": {
          "id": "default-user"
        },
        "locale": "es",
        "text": "No tengo respuesta para eso.",
        "attachments": [],
        "entities": [],
        "replyToId": "61hacck8j6jg",
        "id": "47me557ikbf7"
      },
      "assert": "Request.Text == Response.Text"
    }
  ]
}

ご覧のとおり、次のものがあります。

  • ダイレクトラインシークレット -> 公開ボットからのシークレット
  • 直接トークン生成エンドポイント -> シークレットを使用してトークンを取得するエンドポイント
  • 直接会話エンドポイント -> 会話を操作するためのエンドポイント
  • エントリ -> テストケース
    • リクエスト -> 会話に送信するもの
    • 応答 -> 取得が期待されるもの
    • アサート -> 何を比較しているのか

デシリアライゼーション

json ファイルが完全にフォーマットされているので、それをソリューションにロードする必要があるため、JSON.NET といくつかのクラスを使用します。まず、すべてが含まれるエントリ コレクションがあり、次にコレクションごとにエントリのリストがあります。

    /// <summary>
    /// Object to parse from the file
    /// </summary>
    public class TestEntriesCollection
    {
        /// <summary>
        /// DirectLine Secret
        /// </summary>
        [JsonProperty("secret")]
        public string Secret { get; set; }
        /// <summary>
        /// Endpoint to get the token using the secret for DirectLine
        /// </summary>
        [JsonProperty("directlineGenerateTokenEndpoint")]
        public string DirectLineGenerateTokenEndpoint { get; set; }
        /// <summary>
        /// Endpoint for a conversation in DirectLine
        /// </summary>
        [JsonProperty("directlineConversationEndpoint")]
        public string DirectLineConversationEndpoint { get; set; }
        /// <summary>
        /// Entries list
        /// </summary>
        [JsonProperty("entries")]
        public List<TestEntry> Entries { get; set; }
    }

これは、テスト ケースの名前、要求、応答、およびアサートを持つオブジェクトです。


    public class TestEntry
    {
        /// <summary>
        /// Entry name
        /// </summary>
        [JsonProperty("name")]
        public string Name { get; set; }
        /// <summary>
        /// Activity requested by the entry
        /// </summary>
        [JsonProperty("request")]
        public Activity Request { get; set; }
        /// <summary>
        /// Activity response expected by the entry
        /// </summary>
        [JsonProperty("response")]
        public Activity Response { get; set; }
        /// <summary>
        /// Assert value in string
        /// </summary>
        [JsonProperty("assert")]
        public string Assert { get; set; }
    }

テストケースでの json からオブジェクトへの解析

解析オブジェクトのクラスがあれば、オブジェクトとして読み取る必要があるため、非常に簡単です。

// Load entries from file
var path = System.IO.File.ReadAllText(@"C:\data.json");

// Deserialize to object
var data = JsonConvert.DeserializeObject<TestEntriesCollection>(path);

このコレクションを使用すると、それをループして、たとえば foreach を使用して情報を取得できるようになります。

 foreach (TestEntry entry in data.Entries)
    {
      ....
    }

この部分はこれですべてです。次の部分には DirectLine の認証が含まれます。すべてのコードは this リポジトリの github に保存されていることに注意してください。