Chris van Leeuwen Front-end development, webdesign and more!

Unit Testing URL patterns for URLRewriter.NET

19-5-2009

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).

Test framework & dependencies

  • UrlRewriter.NET 2.0 RC1
  • NUnit 2.4.6
  • Rhino Mocksease 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:

  1. Web Request enters ASP.NET runtime.
  2. RewriterHttpModule is initialized and calls the RewriterEngine.Rewrite() method.
  3. RewriterEngine reads the config and checks which rules match the request.
  4. 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);
Because our 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: , , ,

Leave a Reply


Powered by WordPress 20 queries. 0.300 seconds.