5

I have the following controller:

public sealed class SomeController : Controller
{
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;

        return View("404");
    }
}

I have created an MSpec specification:

[Subject(typeof (SomeController))]
public class when_invalid_page_is_requested : SomeControllerSpec
{
    Because of = () => result = Controller.PageNotFound();

    It should_set_status_code_to_404 = 
        () => Controller.Response.StatusCode.ShouldEqual(404);
}

public abstract class SomeControllerSpec
{
    protected static HomeController Controller;

    Establish context = () => { Controller = new SomeController(); };
}

But because of how I instantiate the controller, HttpContext is null. What would be the best way to test status code set by the PageNotFound action?

EDIT: Posted an answer below

Arnold Zokas
  • 8,306
  • 6
  • 50
  • 76

3 Answers3

6

Found a way to do it using Moq.

[Subject(typeof (SomeController))]
public class when_invalid_page_is_requested : SomeControllerSpec
{
    Because of = () => result = Controller.PageNotFound();

    It should_set_status_code_to_404 = 
        () => HttpResponse.VerifySet(hr => hr.StatusCode = 404);
}

public abstract class SomeControllerSpec
{
    protected static SomeController Controller;
    protected static Mock<ControllerContext> ControllerContext;
    protected static Mock<HttpResponseBase> HttpResponse;

    Establish context = () =>
    {
        ControllerContext = new Mock<ControllerContext>();
        HttpResponse = new Mock<HttpResponseBase>();
        ControllerContext.SetupGet(cc => cc.HttpContext.Response)
                         .Returns(HttpResponse.Object);

        Controller = new SomeController
                         {
                             ControllerContext = ControllerContext.Object
                         };
    };
}

Not very elegant. If you can think of a better way - let me know.

Arnold Zokas
  • 8,306
  • 6
  • 50
  • 76
3

You can use:

_controller.Response.StatusCode
jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • You do need to mock it first. For example by calling `controller.SetMockControllerContext()` from https://gist.github.com/johnnyreilly/4959924#file-mvcmockhelpers-cs. – user2609980 Jun 11 '15 at 00:34
3

Another option using MvcContrib's TestControllerBuilder...

var myController = new MyController();

var testControllerBuilder = new TestControllerBuilder();
testControllerBuilder.InitializeController(myController);

and then using NUnit (I'd guess the Moq version would work just like you have it)...

myController.Response.AssertWasCalled( response => response.StatusCode = 400 );

All the ugly setup and mocking work is still being done, but by MvcContrib instead of inside the test. Here's a post on using the TestControllerBuilder.

StarTrekRedneck
  • 1,957
  • 1
  • 15
  • 15