Thursday, December 13, 2007

More Mocking of HttpContext for MVC

I was actually preparing this for a comment to my last post in answer to chris7's comment. But it got long. You know!

Chris7 asked if it was possible to abstract out the Record/Playback syntax in the example to make the code clearer. And you can of course do that and put the Replay call into the MockContextFactory like this:

protected IHttpContext MockContextFactory(string url)
{
IHttpContext httpContext = mockery.Stub<IHttpContext>();
IHttpRequest httpRequest = mockery.Stub<IHttpRequest>();
SetupResult.For(httpRequest.AppRelativeCurrentExecutionFilePath).Return("~" + url);
SetupResult.For(httpContext.Request).Return(httpRequest);
mockery.Replay(httpRequest);
mockery.Replay(httpContext);
return httpContext;
}


The code in the test method would then look this way:



[Test]
public void WorldDetailsRouteExists1()
{
IHttpContext httpContext = MockContextFactory("/World/Details/9/3");
RouteData routeData = routes.GetRouteData(httpContext);
Assert.IsNotNull(routeData, "There is a route to the URL");
Assert.AreEqual("World", routeData.Values["controller"], "We are using the world controller");
Assert.AreEqual("Details", routeData.Values["action"], "With the details action");
Assert.AreEqual("9", routeData.Values["x"], "And the correct x");
Assert.AreEqual("3", routeData.Values["y"], "And the correct y");
mockery.VerifyAll();
}


I actually chose the Record/Playback model as I find it nicer to look at than the other syntax. But I guess it is a matter of taste. In this example it is probably not obvious why I prefer that syntax, but for more involved mocking scenarios it makes it easier to see what is record and what is playback.



Phil Haacked also commented with a post of his own describing how to the same thing using extension methods instead. I encourage you to look at that as well to see yet another way of doing it.



kick it on DotNetKicks.com

Tuesday, December 11, 2007

Mocking HttpContext for MVC route testing

First I have to say thx a bunch to MS for releasing the CTP of the MCV framework. This really is Da Bomb. I think they are doing a great job here.

So I am setting up my first MVC.NET based site, while digging through all the relevant posts on how to use the framework. So while setting up my routes, doing the proper TDD, I stumble upon the MockHttpContext for testing routes in ScottGu's part 2. This bugger is not explained anywhere nor part of the framework. So you have to whip up your own. Googling it - lazy as I am turned up nothing. DIY time. But being the friendly coder, I will share what I made.

So without further ado - here is how you could create a MockHttpContext for testing your routes using Rhino.Mocks. Note, I have used the same way of setting up the routes as Scott is showing in his post.

[TestFixture]
public class RoutesTest
{
protected RouteCollection routes;
protected MockRepository mockery;

[SetUp]
public void SetUp()
{
routes = new RouteCollection();
Global application = new Global();
application.RegisterRoutes(routes);
mockery = new MockRepository();
}

protected IHttpContext MockContextFactory(string url)
{
IHttpContext httpContext = mockery.Stub<IHttpContext>();
IHttpRequest httpRequest = mockery.Stub<IHttpRequest>();
SetupResult.For(httpRequest.AppRelativeCurrentExecutionFilePath).Return("~" + url);
SetupResult.For(httpContext.Request).Return(httpRequest);
return httpContext;
}

[Test]
public void TestRouteRegistration()
{
Assert.IsNotEmpty(routes, "We have filled the routes list");
}

[Test]
public void SearchRouteExists()
{
IHttpContext httpContext;
using (mockery.Record())
{
httpContext = MockContextFactory("/Search/Beverages/2");
}
using (mockery.Playback())
{
RouteData routeData = routes.GetRouteData(httpContext);
Assert.IsNotNull(routeData, "There is a route to the URL");
Assert.AreEqual("Search", routeData.Values["controller"], "We are using the search controller");
Assert.AreEqual("Results", routeData.Values["action"], "With the details action");
Assert.AreEqual("Beverages", routeData.Values["query"], "And the correct query");
Assert.AreEqual("2", routeData.Values["page"], "And the correct page index");
}
}
}
kick it on DotNetKicks.com