【问题标题】:ASP.NET MVC Moq unit testing against a controller that returns FileStreamResult针对返回 FileStreamResult 的控制器的 ASP.NET MVC Moq 单元测试
【发布时间】:2011-05-04 05:14:56
【问题描述】:

我正在编写一个针对返回 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 为空。

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

非常感谢!

杰弗里

【问题讨论】:

    标签: asp.net-mvc unit-testing filestreamresult


    【解决方案1】:

    您需要mock the 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");
    }
    

    【讨论】:

      【解决方案2】:

      根据 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();
              }
          }
      

      【讨论】:

        【解决方案3】:

        这是一个经典的测试问题。这是因为这更像是一个集成测试而不是一个单元测试(涉及文件系统)。

        在 ASP.Net Web Forms 时代,模拟 HTTP 上下文一直是一个主要问题。也许您的测试应该专注于 HelpPageBusinessService。

        如果所有其他方法都失败,则可能通过依赖注入将帮助程序类传递给您的控制器,该控制器会添加标头或带有模拟框架的模拟。

        【讨论】:

        • 非常感谢您的回复,我非常同意您的看法。事实上,我已经针对“HelpPageBusinessService”制作了一个测试用例。只是因为项目代码标准要求 80% 的单元测试覆盖率,我必须针对这个控制器编写一个测试用例。 :)
        【解决方案4】:

        使用 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"));
        

        【讨论】:

          猜你喜欢
          • 2023-03-15
          • 1970-01-01
          • 1970-01-01
          • 2016-08-14
          • 1970-01-01
          • 2014-12-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多