3

controllerContext をパラメーターとして使用して、第 3 部ライブラリ「Rotativa」に基づいて PDF ドキュメントを生成するアクションをコントローラーでテストしたいと考えています。
アクション(関数)の実装は次のとおりです。

public ActionResult DetailsPrint(int? id)
{
    var a = new ViewAsPdf();
    a.ViewName = "../Ops/_2A1/Details";
    a.Model =UnitOfWork._2A1s.Get(id.Value);
    var pdfBytes = a.BuildPdf(ControllerContext);

    // return ActionResult
    MemoryStream ms = new MemoryStream(pdfBytes);
    return new FileStreamResult(ms, "application/pdf");

}

そして、これが私が単体テストを機能させようとしている方法です:

  • コンストラクタ

    public _2A1ControllerTest()
    {
        _mockRepository = new Mock<I2A1Repository>();
        var mockUoW = new Mock<IUnitOfWork>();
        _mockHttpContext = new Mock<HttpContextBase>();
        _mockRequest = new Mock<HttpRequestBase>();
        _mockDisplayModeContext = new Mock<IDisplayMode>();
        mockUoW.SetupGet(u => u._2A1s).Returns(_mockRepository.Object);
        _mockHttpContext.SetupGet(x => x.Request).Returns(_mockRequest.Object);
        _controller = new _2A1Controller(mockUoW.Object);
        _controller.MockCurrentUser("test.admin");
        _controller.ControllerContext = new ControllerContext(_mockHttpContext.Object, new System.Web.Routing.RouteData(), _controller);
    }
    
  • テスト機能

    [TestMethod]
    public void DetailsPrint_shouldPrint()
    {
        var result = _controller.DetailsPrint(1) as ActionResult;
        result.Should().BeOfType<ActionResult>();
    }
    

    テストを実行すると、次のエラーが発生します。 ここに画像の説明を入力

テスト名: DetailsPrint_shouldPrint テスト フルネーム: OPSReviewTest._2A1ControllerTest.DetailsPrint_shouldPrint テスト ソース: C:\inetpub\wwwroot\OpsReview\OPSReviewTest\Controllers\Api_2A1ControllerTest.cs: 46 行目 テスト結果: 失敗 テスト期間: 0:04:39,3039007 結果 StackTrace :
System.Web.WebPages.DisplayModeProvider.GetDisplayMode(HttpContextBase コンテキスト) で System.Web.Mvc.ControllerContext.get_DisplayMode() 結果メッセージ: テスト メソッド OPSReviewTest._2A1ControllerTest.DetailsPrint_shouldPrint が例外をスローしました: System.NullReferenceException: オブジェクト参照が設定されていませんオブジェクトのインスタンス。

助けや提案、ありがとう。

4

2 に答える 2

1

所有していないコードを単体テストしようとしていますか? (恥、[鐘が鳴る]、恥…)

コントローラーのアクション フローを単独でテストすることが目的である場合は、サード パーティの PDF 生成を抽象化して、テストを容易にするためにモックできるようにすることをお勧めします。

public interface IViewAsPdfWrapper {
    string ViewName { get; set; }
    object Model { get; set; }
    byte[] BuildPdf(ControllerContext context);
}

public class ViewAsPdfWrapper : IViewAsPdfWrapper {
    private readonly ViewAsPdf view;
    public ViewAsPdfWrapper() {
        view = new ViewAsPdf();
    }
    public string ViewName { get; set; }
    public object Model { get; set; }
    public byte[] BuildPdf(ControllerContext context) {
        view.ViewName = ViewName;
        view.Model = Model;
        return view.BuildPdf(context);
    }
}

抽象化をコントローラーに注入して、必要に応じて要求アクションごとに使用できるようになりました。

public class _2A1Controller : Controller {
    private readonly IUnitOfWork UnitOfWork;
    private readonly IViewAsPdfWrapper viewAsPdf;

    public _2A1Controller(IUnitOfWork uow, IViewAsPdfWrapper viewAsPdf) {
        this.UnitOfWork = uow;
        this.viewAsPdf = viewAsPdf;
    }

    public ActionResult DetailsPrint(int? id) {
        var a = viewAsPdf;
        a.ViewName = "../Ops/_2A1/Details";
        a.Model = UnitOfWork._2A1s.Get(id.Value);
        var pdfBytes = a.BuildPdf(ControllerContext);

        // return ActionResult
        MemoryStream ms = new MemoryStream(pdfBytes);
        return new FileStreamResult(ms, "application/pdf");
    }

}

これで、単体テストでサードパーティの機能を安全にモックできるようになりました

public _2A1ControllerTest() {    
    _mockRepository = new Mock<I2A1Repository>();
    var mockUoW = new Mock<IUnitOfWork>();
    mockUoW.SetupGet(u => u._2A1s).Returns(_mockRepository.Object);

    var mockViewAsPdf = new Mock<IViewAsPdfWrapper>();
    mockViewAsPdf.Setup(m => m.BuildPdf(It.IsAny<ControllerContext>()))
        .Returns(() => new byte[0]);

    _mockRequest = new Mock<HttpRequestBase>();
    _mockHttpContext = new Mock<HttpContextBase>();
    _mockHttpContext.SetupGet(x => x.Request).Returns(_mockRequest.Object);

    _controller = new _2A1Controller(mockUoW.Object, mockViewAsPdf.Object);
    _controller.MockCurrentUser("test.admin");
    _controller.ControllerContext = new ControllerContext(_mockHttpContext.Object, new System.Web.Routing.RouteData(), _controller);

}

FluentAssertions の使用を想定すると、テスト メソッドは次のようになります (しゃれが意図されています :))

[TestMethod]
public void DetailsPrint_shouldPrint() {
    var result = _controller.DetailsPrint(1) as ActionResult;
    result.Should()
        .NotBeNull()
        .And
        .BeAssignableTo<ActionResult>();
}

最後に、インターフェイスとその実装を本番環境の DI コンテナーに登録することを忘れないでください。

于 2016-11-26T06:47:16.573 に答える