0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Bot Builder v4.5 のユニットテスト : コントローラーのテスト

Posted at

今回でこのシリーズは最終回です。
前回までダイアログのテストを見ていきましたが、今回はコントローラーのテストを見ていきます。

コントローラーのテスト

Bot Builder v4 でのユニットテストを連載した際は、コントローラーはボットの実行に直接関係が薄く、また変更することもあまりないことから、あまりテストをしませんでした。今回はテンプレートに含まれているため、しっかりとテストしておきましょう。

PostAsyncCallsProcessAsyncOnAdapter テスト

BotBuilder で開発するボットは実質 Web API であり、POST メソッドを待ち受ける 1 つのコントローラーです。よってテストも Post メソッドのテスト 1 つのみです。

[Fact]
public async Task PostAsyncCallsProcessAsyncOnAdapter()
{
    // Create MVC infrastructure mocks and objects
    var request = new Mock<HttpRequest>();
    var response = new Mock<HttpResponse>();
    var mockHttpContext = new Mock<HttpContext>();
    mockHttpContext.Setup(x => x.Request).Returns(request.Object);
    mockHttpContext.Setup(x => x.Response).Returns(response.Object);
    var actionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ControllerActionDescriptor());

    // Create BF mocks
    var mockAdapter = new Mock<IBotFrameworkHttpAdapter>();
    mockAdapter
        .Setup(x => x.ProcessAsync(It.IsAny<HttpRequest>(), It.IsAny<HttpResponse>(), It.IsAny<IBot>(), It.IsAny<CancellationToken>()))
        .Returns(Task.CompletedTask);
    var mockBot = new Mock<IBot>();

    // Create and initialize controller
    var sut = new BotController(mockAdapter.Object, mockBot.Object)
    {
        ControllerContext = new ControllerContext(actionContext),
    };

    // Invoke the controller
    await sut.PostAsync();

    // Assert
    mockAdapter.Verify(
        x => x.ProcessAsync(
            It.Is<HttpRequest>(o => o == request.Object),
            It.Is<HttpResponse>(o => o == response.Object),
            It.Is<IBot>(o => o == mockBot.Object),
            It.IsAny<CancellationToken>()),
        Times.Once);
}

各種サービスのモック

依存するサービスを Moq フレームワークでモックします。

HTTP 要求と応答および HttpConetxt

実際に誰から要求を送ってくるわけではないため、要求と応答をモックします。

var request = new Mock<HttpRequest>();
var response = new Mock<HttpResponse>();
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(x => x.Request).Returns(request.Object);
mockHttpContext.Setup(x => x.Response).Returns(response.Object);

ActionContext のモック

テンプレートは ASP.NET Core 2.1 ベースのため、 Microsoft.AspNetCore.Mvc 名前空間の ActionContext もモックしています。後程 ControllerContext に渡されます。

var actionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ControllerActionDescriptor());

アダプターのモック

コントローラーから呼び出される BotBuilder のコンポーネントはアダプターです。また ProcessAsync メソッドが実行されます。詳細は Bot Builder v4 でボット開発 : アダプター、TurnContext、Activity を参照してください。

var mockAdapter = new Mock<IBotFrameworkHttpAdapter>();
mockAdapter
    .Setup(x => x.ProcessAsync(It.IsAny<HttpRequest>(), It.IsAny<HttpResponse>(), It.IsAny<IBot>(), It.IsAny<CancellationToken>()))
    .Returns(Task.CompletedTask);

IBot のモック

特定のボットを起動するテストではないため、 IBot もモックします。

var mockBot = new Mock<IBot>();

テストの実行

テストはシンプルにコントローラーに対して Post を実行します。

// Create and initialize controller
var sut = new BotController(mockAdapter.Object, mockBot.Object)
{
    ControllerContext = new ControllerContext(actionContext),
};

// Invoke the controller
await sut.PostAsync();

結果の検証

結果はアダプタで一度だけ ProcessAsync が呼ばれたかを確認します。

// Assert
mockAdapter.Verify(
    x => x.ProcessAsync(
        It.Is<HttpRequest>(o => o == request.Object),
        It.Is<HttpResponse>(o => o == response.Object),
        It.Is<IBot>(o => o == mockBot.Object),
        It.IsAny<CancellationToken>()),
    Times.Once);

まとめ

このシリーズでは BotBuilder SDK v4.5 で提供されたユニットテスト機能を見てきました。TestFlow や TestAdapter、IRecognizer などの利用についてはこれまで通りですが、テンプレートとしてはじめからユニットテスト付きのソリューションを作れることが最大のポイントだと考えています。是非ユニットテストを充実させて、DevOps を実現してください。

目次へ戻る

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?