3

I am writing a test case against a controller that returns a pdf file.

Code for controller :

  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");
    }

Unit test code :

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

This unit test case does not work, it always fail as HttpContext is null.

Does anybody out there know how to write unit test case against this type of controller ?

Much appreciated !

Jeffery

Nat
  • 14,175
  • 5
  • 41
  • 64
jeffreychi
  • 199
  • 3
  • 14

4 Answers4

6

You need to mock the HttpContext and the response objects. Also your controller action could be shortened a bit:

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");
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
4

Following Darin Dimitrov's recommendation, I have came up with the following code. :)

 [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();
        }
    }
jeffreychi
  • 199
  • 3
  • 14
1

This is a classic testing issue. It stems from the fact this is more of an integration test rather than a unit test (touching the file system).

Mocking HTTP context has been a major issue back through the ASP.Net Web Forms era.Perhaps your test should focus on the HelpPageBusinessService.

If all else fails perhaps pass a helper class via dependency injection to your controller, that adds the header or mock with a mocking framework.

merbla
  • 537
  • 6
  • 14
  • Thank you very much for your response, I quite agree with you. As matter of fact, I already have produced a test case against the "HelpPageBusinessService". It is just because of the project code standards require 80% unit testing coverage, I have to write a test case against this controller. :) – jeffreychi Nov 02 '10 at 23:49
0

Using MOQ, you can even test if the header has been actually added to the response object

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 }
};

Then you can verify

_httpResponse.Verify(r => r.AddHeader("content-disposition", "attachment; filename=GSFA_Help_Pages_Printout.pdf"));
nabeelfarid
  • 4,156
  • 5
  • 42
  • 60