Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

ボット開発でも DevOps! BotBuilder のテスト手法

166 views

Published on

de:code 2019 AI02 セッション資料

Published in: Technology
  • Be the first to comment

ボット開発でも DevOps! BotBuilder のテスト手法

  1. 1. de:code 2019 AI02 チャットボット開発でも DevOps! BotBuilder のテスト手法 日本マイクロソフト株式会社 Sr. Software Engineer 中村 憲一郎
  2. 2. 本セッションのゴール 400
  3. 3. 前提となる知識
  4. 4. 中村 憲一郎 Sr. Software Engineer 好きな技術は主に、C#, UWP, Xamarin, API, PowerShell, DB, Node.js https://github.com/kenakamu https://qiita.com/kenakamu
  5. 5. ブログ
  6. 6. ブログ
  7. 7. 前提 チャットボットをはじめとする モダンアプリケーションは 進化を続けるために頻繁に 更新を行う必要がある
  8. 8. DevOps
  9. 9. DevOps : ビルド
  10. 10. デプロイ先環境 : 複数環境の用意
  11. 11. Bot Channels Registration の制限
  12. 12. Web App : 複数スロットを利用 - スワップのため
  13. 13. Web App : スロット毎にユニークな設定が可能
  14. 14. リリースパイプライン
  15. 15. 手動認証
  16. 16. DevOps ユニットテスト
  17. 17. チャットボットのライフサイクル
  18. 18. チャットボットのユニットテスト • ユニットはどの単位か
  19. 19. ユニットはどの単位か
  20. 20. TestFlow TestAdapter テストフレームワーク
  21. 21. TestFlow
  22. 22. ブラックボックス (外部サービス) の例
  23. 23. TestFlow デモ
  24. 24. ユニットテストに必要な ボット動作の理解
  25. 25. ボットに要求が来るまで
  26. 26. ステート管理
  27. 27. ミドルウェア
  28. 28. ステートのテスト
  29. 29. デモ
  30. 30. コンストラクターでステートを渡す public SessionEchoBot ( ConversationState conversationState, UserState userState, )
  31. 31. テスト側でステートの作成 // ストレージとしてインメモリを利用 IStorage dataStore = new MemoryStorage(); var conversationState = new ConversationState(dataStore); var userState = new UserState(dataStore);
  32. 32. ボットのインスタンス作成 var bot = new SessionEchoBot ( conversationState, userState );
  33. 33. テストコード await new TestFlow(new TestAdapter(), bot.OnTurnAsync) .Test(“Hi”, “Hi 1”) .Test(“Yo”, “Yo 2”) .StartTestAsync();
  34. 34. ダイアログのユニットテスト
  35. 35. デモ
  36. 36. TestFlow で Lambda を使用 var testFlow = new TestFlow( adapter, async (turnContext, cancellationToken) => { var dialogContext = await dialogs.CreateContextAsync( turnContext, cancellationToken);
  37. 37. ステート : アダプタのミドルウェアで保存 var adapter = new TestAdapter(); adapter.Use( new AutoSaveStateMiddleware(conversationState));
  38. 38. DialogSet を追加 var dialogState = conversationState.CreateProperty<DialogState> ("DialogState"); var dialogs = new DialogSet(dialogState); dialogs.Add(new ProfileDialog ());
  39. 39. ダイアログコンテキスト作成 var testFlow = new TestFlow(adapter, async (turnContext, cancellationToken) => { var dialogContext = await dialogs.CreateContextAsync( turnContext, cancellationToken);
  40. 40. ダイアログのライフサイクル : 継続と開始 var results = await dialogContext. ContinueDialogAsync(cancellationToken); if (results.Status == DialogTurnStatus.Empty) { results = await dialogContext.BeginDialogAsync( nameof(ProfileDialog), new Profile(), cancellationToken); }
  41. 41. ダイアログのライフサイクル : 完了 if (results.Status == DialogTurnStatus.Complete) { await turnContext.SendActivityAsync("Done"); }
  42. 42. テスト await testFlow .Test("開始", "名前は?") .Test("中村", "🐈派?🐕派?") .Send("🐈派") .AssertReply(activity => { Assert.AreEqual("Done", (activity as Activity).Text); }) .StartTestAsync();
  43. 43. プロンプトのリトライ
  44. 44. デモ
  45. 45. テスト await testFlow .Test("開始", "名前は?") .Test("中村", "🐈派?🐕派? (1) 🐈派 or (2) 🐕派") .Test("🐇派", "🐈か🐕で答えてください。 (1) 🐈派 or (2) 🐕派") ….
  46. 46. 外部サービスのモック化 LUIS
  47. 47. デモ
  48. 48. LuisRecognizer と IRecognizer
  49. 49. IRecognizer var luisApplication = new LuisApplication(key, key, uri); var recognizer = new LuisRecognizer(luisApplication); services.AddSingleton<IRecognizer>(recognizer);
  50. 50. Dependency Injection 対応 public MyBotWithLuis( ConversationState conversationState, UserState userState, IRecognizer recognizer) {
  51. 51. モックの作成 var mockRecognizer = new Mock<IRecognizer>(); mockRecognizer.Setup(l => l.RecognizeAsync(…) .Returns((…) =>
  52. 52. 応答の作成 var recognizerResult = new RecognizerResult() { Intents = new Dictionary<string, IntentScore>(), Entities = new JObject() };
  53. 53. 応答の作成 : インテント case "今日の天気を確認": recognizerResult.Intents.Add( "Weather", new IntentScore() { Score = 1 }); recognizerResult.Entities.Add( "day", JArray.Parse("[['今日']]")); break;
  54. 54. DataRow を使ったテスト [TestMethod] [DataRow("今日")] [DataRow("明日")] public async Task TestName(string day){ var arrange = Arrange().testFlow; await testFlow.Test("天気を確認", "いつの天気を知….. .Test(day, $"{day}の天気は晴れです") .StartTestAsync(); }
  55. 55. ダイアログ遷移を スタック情報で検証
  56. 56. デモ
  57. 57. AssertReply 内で TurnContext を作成 .AssertReply(activity => { var turnContext = new TurnContext( adapter, activity as Activity);
  58. 58. DialogContext の ActiveDialog を検証 .AssertReply(activity => { var turnContext = new TurnContext( adapter, activity as Activity); var dc = dialogs.CreateContextAsync( turnContext).Result; Assert.AreEqual(nameof(ProfileWithChoiceDialog), dc.ActiveDialog.Id);
  59. 59. システムメッセージ
  60. 60. デモ
  61. 61. システムメッセージ : Activity var act = new Activity(ActivityTypes.ConversationUpdate){ Id = "test", From = new ChannelAccount("TestUser", "Test User"), ChannelId = "UnitTest", ServiceUrl = "https://example.org", MembersAdded = new List<ChannelAccount>() { new ChannelAccount("TestUser", "Test User") } };
  62. 62. TestFlow.Send await new TestFlow(adapter, bot.OnTurnAsync) .Send(conversationUpdateActivity) .AssertReply(activity => { …
  63. 63. リンクファイル
  64. 64. 外部サービスのモック化 OAuthPrompt & Graph
  65. 65. デモ
  66. 66. OAuthPrompt のモック var adapter = new TestAdapter(); adapter.AddUserToken("AADv2", "test", "user1", "dummyToken");
  67. 67. MSGraph のモック mockGraphSDK.Setup(x => x.Me.CalendarView.Request(It.IsAny<List<QueryOption>>()).Ge tAsync()).ReturnsAsync(() => { var page = new UserCalendarViewCollectionPage(); page.Add(new Event(){ Subject = "Dummy 1", Start = … End = … } });
  68. 68. その他にも
  69. 69. 本セッションのゴール 400
  70. 70. © 2018 Microsoft Corporation. All rights reserved. 本情報の内容(添付文書、リンク先などを含む)は、作成日時点でのものであり、予告なく変更される場合があります。 © 2019 Microsoft Corporation. All rights reserved. 本情報の内容 (添付文書、リンク先などを含む) は、de:code 2019 開催日 (2019年5月29~30日) 時点のものであり、予告なく変更される場合があります。 本コンテンツの著作権、および本コンテンツ中に出てくる商標権、団体名、ロゴ、製品、サービスなどはそれぞれ、各権利保有者に帰属します。

×