ASP.NET MVC Moq单元测试控制器返回FileStreamResult的方法

3

我是一名有用的助手,可以为你进行翻译。

我正在撰写一个针对返回PDF文件的控制器的测试用例。

控制器代码如下:

  public FileStreamResult GeneratePdfReport(string context)
    {
        byte[] pdfReportContents = _helpPageBusinessService.GetHelpPagesAsPdf();
        Stream stream = new MemoryStream(pdfReportContents);
        HttpContext.Response.AddHeader("content-disposition", "attachment; filename=GSFA_Help_Pages_Printout.pdf");
        return new FileStreamResult(stream, "application/pdf");
    }

单元测试代码:

 [TestMethod]
    public void GeneratePdf()
    {
        var controller = new HelpController(_helpPageBusinessServiceReportServices, Logger);
        try
        {
            var result = controller.GeneratePdfReport("Work_Request_Section");
            Assert.IsNotNull(result);
            Assert.IsNotNull(result.FileStream);
        }
        finally
        {
            controller.Dispose();
        }
    }

这个单元测试用例不能工作,因为HttpContext为空,导致测试总是失败。

有没有人知道如何编写针对这种类型的控制器的单元测试用例?

非常感谢!

Jeffery

4个回答

6

你需要模拟HttpContext和响应对象。此外,你的控制器操作可以简化一些:

public ActionResult GeneratePdfReport(string context)
{
    byte[] pdfReportContents = _helpPageBusinessService.GetHelpPagesAsPdf();
    HttpContext.Response.AddHeader("content-disposition", "attachment; filename=GSFA_Help_Pages_Printout.pdf");
    return File(pdfReportContents, "application/pdf");
}

4

根据Darin Dimitrov的建议,我想出了以下代码。:)

 [TestMethod]
    public void GeneratePdf()
    {
        var controller = new HelpController(_helpPageBusinessServiceReportServices, Logger);
        var httpContextBase = new Mock<HttpContextBase>
        {
            DefaultValue = DefaultValue.Mock
        };
        var responseObject = Mock.Get(httpContextBase.Object.Response);
        responseObject.Setup(
            s => s.AddHeader("content-disposition", "attachment; filename=GSFA_Help_Pages_Printout.pdf"));
        controller.ControllerContext = new ControllerContext(httpContextBase.Object, new RouteData(), controller);
        try
        {
            var result = controller.GeneratePdfReport("Work_Request_Section");
            Assert.IsNotNull(result);
            Assert.IsNotNull(result.FileStream);
            Assert.IsTrue(result.FileStream.Length == 2000);
        }
        finally
        {
            controller.Dispose();
        }
    }

1
这是一个经典的测试问题。它源于这更像是一个集成测试而不是单元测试(涉及文件系统)。
模拟HTTP上下文在ASP.Net Web Forms时代一直是一个主要问题。也许你的测试应该关注HelpPageBusinessService。
如果其他方法都失败了,可以通过依赖注入将帮助类传递给控制器,添加头部或使用模拟框架进行模拟。

非常感谢您的回复,我非常同意您的观点。事实上,我已经针对“HelpPageBusinessService”编写了一个测试用例。只是因为项目代码标准要求80%的单元测试覆盖率,所以我不得不针对这个控制器编写一个测试用例。 :) - jeffreychi

0
使用MOQ,您甚至可以测试标题是否已实际添加到响应对象中。
var httpContextBase = new Mock<HttpContextBase>();
_httpResponse = new Mock<HttpResponseBase>();
httpContextBase.Setup(c => c.Response).Returns(_httpResponse.Object);
controller = new Controller(businessService.Object)
{
     ControllerContext = new ControllerContext { HttpContext = httpContextBase.Object }
};

然后您可以进行验证

_httpResponse.Verify(r => r.AddHeader("content-disposition", "attachment; filename=GSFA_Help_Pages_Printout.pdf"));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接