jeffreychi
jeffreychi

Reputation: 199

ASP.NET MVC Moq unit testing against a controller that returns FileStreamResult

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

Upvotes: 3

Views: 5118

Answers (4)

nabeelfarid
nabeelfarid

Reputation: 4224

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

Upvotes: 0

Darin Dimitrov
Darin Dimitrov

Reputation: 1038890

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

Upvotes: 6

jeffreychi
jeffreychi

Reputation: 199

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

Upvotes: 4

merbla
merbla

Reputation: 547

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.

Upvotes: 1

Related Questions