In a current project I am using URLRewriter.NET to create readable URL patterns. To ensure my rewrite rules are valid I created some Unit Tests (using NUnit and Rhino.Mocks).
- Download tutorial code (Visual Studio 2008 project)
Test framework & dependencies
- UrlRewriter.NET 2.0 RC1
- NUnit 2.4.6
- Rhino Mocks — ease testing by allowing the developer to create mock implementations of custom objects and verify the interactions using unit testing.
Don’t be scared of Rhino Mocks, it’s my first time too
It’s really easy once you see an example!
Test Case
In this example I want to check if the url “/users/chris/” is correctly rewritten to a ASP.NET page: “/view_user.aspx?name=chris“. Let’s start with setting up our test case:
[Test]
public void ViewUserTest() {
TestShouldRewriteUrl("/users/chris/", "/view_user.aspx?name=chris");
}
Following the TDD mantra our Unit Test fails, which means we have a job to do!
Test method
The Test will have to implement the following features:
- Initialize the URL Rewriter framework as if a new webrequest is being handled.
- Simulate a web request and invoke the URL Rewriter
- Validate the URL Rewriter correctly rewrites our testcase.
A closer look at the inner workings of URL Rewriter
Because we are testing our config and validating it against our test case, we need to find out how URL Rewriter works internally. The typical flow for a URL Rewriter request is as follows:
- Web Request enters ASP.NET runtime.
RewriterHttpModuleis initialized and calls theRewriterEngine.Rewrite()method.RewriterEnginereads the config and checks which rules match the request.- Rewrite rule is invoked, which transfers the request to the actual page, by using the
HttpContext.
A closer look at the RewriterEngine shows URL Rewriter was build with testability in mind, phew! Instead of directly accessing the ASP.NET HttpContext the briliant author wrapped the HttpContext in the IContextFacade. This means all we have to do is monitor the IContextFacade and check if the request is transfered as expected.
Mocking IContextFacade to validate our test case
To monitor the IContextFacade, we can create a “mock” implementation (using Rhino Mocks) and monitor it to validate our test case. Creating a mock is very easy:
MockRepository mockRepository = new MockRepository(); // All resulting actions by rewrite rules are executed on the IContextFacade IContextFacade contextFacadeMock = mockRepository.CreateMock<IContextFacade>(); // The core of URL Rewriter RewriterEngine rewriterEngine = new RewriterEngine( contextFacadeMock, RewriterConfiguration.Current);
IContextFacade is just an empty shell at this moment, we need to tell what to do when URL Rewriter invokes methods on it. You do this by using the Rhino Mocks framework. This first code sample instructs the mock to expect a call on the GetHttpMethod(), and that we want to return “GET” as a result:
// Tell the IContextFacade Mock to expect a call
// on GetHttpMethod() and return "GET" when it does.
Expect.Call(contextFacadeMock.GetHttpMethod()).Return("GET");
For this tutorial I have implemented all required methods for our test case:
Expect.Call(contextFacadeMock.GetHttpMethod()).Return("GET");
Expect.Call(contextFacadeMock.GetServerVariables())
.Return(new NameValueCollection());
Expect.Call(contextFacadeMock.GetHeaders()).Return(new NameValueCollection());
Expect.Call(contextFacadeMock.GetCookies()).Return(new HttpCookieCollection());
Expect.Call(contextFacadeMock.GetApplicationPath()).Return("/").Repeat.Any();
// Tell mock to expect call on void method.
Expect.Call(delegate { contextFacadeMock.SetItem(null, null); })
.Repeat.Any().IgnoreArguments();
Expect.Call(delegate { contextFacadeMock.SetStatusCode(0); }).IgnoreArguments();
// mappath is important because of ~/ url's in the rewriter config.
Expect.Call(contextFacadeMock.MapPath).Return(
delegate(string path) { return path.Replace("~", ""); }).Repeat.Any();
With all these collateral methods finally implemented, we need to tell our mock our test case input:
// Let the mock return our test case input
Expect.Call(contextFacadeMock.GetRawUrl())
.Return("/user/chris/").Repeat.Any();
Expect.Call(contextFacadeMock.GetRequestUrl())
.Return(new Uri("http://www.example.org/user/chris/")).Repeat.Any();
If a rewrite rule matches the request, URL Rewriter calls the RewritePath. So our test case will expect a call on RewritePath with our resulting url:
// expected behaviour contextFacadeMock.RewritePath(expectedRelativeUri);
We have now completed our mock. We’re now ready to validate our test case.
mockRepository.ReplayAll(); // Invoke URL Rewriter rewriterEngine.Rewrite(); // Validate the test case, this method will throw an exception // if RewritePath is not called with the expected output. mockRepository.VerifyAll();
Solving our Test Case
With all this code in place we have completed our IContextFacade mock, but our test still fails (which is a good thing). We’re now ready to add our rule in the URL Rewriter config:
<rewriter> <rewrite url="~/users/(.*)/" to="~/view_user.aspx?name=$1" processing="stop" /> </rewriter>
Run our test again and success! Hope this helps you in testing your routes, but please let me know if you have any suggestions! Special thanks to Jeroen Bok for helping me write the test and introducing Rhino Mocks
Tags: .net, RhinoMocks, unit test, URL Rewriter
This is the professional blog of Christian van Leeuwen, Senior Consultant Web Strategy at Deloitte Consulting. I like talking about topics such as front-end development, interaction design and web development.
Leave a Reply