views:

304

answers:

2

I am trying out the MOQ framework and up now I have hit a barrier. The following unit test fails because the actual value of the ViewName property is an empty string.

Could anyone point me in the right direction please as to why this is not passing the test?

[TestMethod]
public void Can_Navigate_To_About_Page()
{
    var request = new Mock<HttpRequestBase>();
    request.Setup(r => r.HttpMethod).Returns("GET");
    var mockHttpContext = new Mock<HttpContextBase>();
    mockHttpContext.Setup(c => c.Request).Returns(request.Object);

    var controllerContext = new ControllerContext(mockHttpContext.Object, 
                                new RouteData(), 
                                new Mock<ControllerBase>().Object);
    var controller = new HomeController();

    controller.ControllerContext = controllerContext;
    var result = controller.About() as ViewResult;

    Assert.AreEqual("About", result.ViewName);
}

The following also yields an empty ViewName.

        HomeController controller = new HomeController();
        ViewResult result = controller.About() as ViewResult;
        Assert.IsNotNull(result);
        Assert.AreEqual("About", result.ViewName);

From examples on the web which demonstrate mocking and also good TTD I am just confused as to what other plumbing I need to make either of the above first unit test example work.

Cheers,

Andrew

+6  A: 

The reason the test is failing is because what decides the ViewName when you do not specify one explicitly is in the depths of the framework. More precisely in the view engine I believe. So to test this as it stands you would have to mock out a lot more of the request pipeline.

What I do, and would recommend, is to not rely on the defaults and specify the view explicitly:

return View("About");

Then the value will be there to test without mocking anything:

var controller = new HomeController();
var result = controller.About() as ViewResult;
Assert.AreEqual("About", result.ViewName);
Garry Shutler
Thankyou, after seeing one of the method signatures is View(string viewName, object model) your point makes perfect sense! P.s. the test passed! :-)
REA_ANDREW
A: 

This is because you're making assumptions about how the MVC framework works. If you're relying on the conventions to locate the view, the framework actually leaves the ViewName property as String.Empty until ExecuteResult() is called.

You can see this code on line 68 of ViewResultBase.ExecuteResult within the MVC source:

if (String.IsNullOrEmpty(ViewName)) {
   ViewName = context.RouteData.GetRequiredString("action");
}

Furthermore, you should be careful about what you're testing. As a rule of thumb, you should focus on testing the code you write, not the framework's code. Testing to make sure the view name by convention is resolved correctly is really a unit test for the framework itself, not an application built on it.

If you're looking for a good way to employ mocking in MVC, you may want to look at testing your routes (which sort of looks like what you're trying to do here). You can find a post by Phil Haack concerning just this subject to get you started.

krohrbaugh