Jun 09 2008
Castle Demo App #4: Unit testing Monorail web sites
One of the best things about Castle Monorail MVC engine is that it allows us to test controllers from the IDE, without actually deploying anything to the web server. A major problem with most web development environments, including classic ASP.NET, is that the workflow and session logic can only be tested through the UI. User interface testing is slow, pain to maintain and generally does not pay off as much as code unit tests do. Monorail’s programming model allows us to test workflow and session logic from the code, leaving only the actual rendering outside the reach of unit tests. That is how Monorail empowers us to really apply agile principles to web development, and saves us even more time and effort.
For those of you that have just joined this tutorial, this is the fourth iteration of the EvilLink web application, that I am building as a way to demonstrate features of the Castle Project application framework and to present some of the best practices for web application development using the Castle Project. Previous articles in this tutorials are:
- ActiveRecord basics and unit testing
- Monorail basics
- Saving time and effort with advanced Monorail features
So far, we have developed a skeleton of the web application that has user operations and link management functionality. Now we write some unit tests for the controllers.
A quick note before we begin. If you are in UK this week, you might want to come to the free session on developing Ajax applications with Monorail that will take place on Thursday (12/06) afternoon at Skills Matter offices in London. This will give us a chance to discuss any questions about this application as well face to face.
Isolating controllers
The first thing we need to do in order to make our controllers unit testable is to isolate them from any external dependencies, including the System.Web.Http objects. Most of the code that would normally be bound to those objects is handled by Monorail anyway. The only place where System.Web objects are used directly is in the UserContext session wrapper. So let’s replace the UserContext object with an interface and a default implementation. Then we can provide a dummy or mock implementation for unit testing.
using System.Web; using EvilLink.Database; namespace EvilLink.Controllers { public interface IUserContext { int? CurrentUserId { get; set;} User CurrentUser { get; } } public class WebUserContext:IUserContext { public int? CurrentUserId { get { return System.Web.HttpContext.Current.Session["currentUserId"] as int?; } set { System.Web.HttpContext.Current.Session["currentUserId"] = value; } } public User CurrentUser { get { return User.Find(CurrentUserId); } } } }
Now we have to propagate this change to the controllers. Change the field type to IUserContext and create two constructors. The no-parameter constructor will automatically set the default implementation so that our application continues to work as before, but we can also set the context from the outside using the constructor with a parameter.
public class UserOpsController : SmartDispatcherController { private IUserContext context; public UserOpsController(){ context=new WebUserContext(); } public UserOpsController(IUserContext ctx) { context = ctx; }
This is how we would mock out any external services that controllers may be connecting to or other stuff that prevents unit testing. At the moment, the controllers are still tied to the default implementation with a compile-time dependency. In the next article of this tutorial we look into better ways to handle that, using the Windsor dependency injection container.
Completely detaching from the real Web
Now create a new project in the solution, called EvilLink.Controllers.Test. Add references to Castle.ActiveRecord, Castle.Monorail.Framework, Castle.Monorail.TestSupport, NHibernate and nunit.framework DLLs. Also add references to EvilLink.Controllers, EvilLink.Database and EvilLink.Database.Test projects that we have developed so far. This new project will host our controller unit tests.
The Castle.Monorail.TestSupport library has almost all the support we need to unit test controllers. It provides us with a mock HTTP environment implementation that allows controllers to execute and be inspected in the code. Class BaseControllerTest does all the heavy lifting, we just need to subclass it and call PrepareController to initialize the controller. Then we can execute any of the controller methods directly and verify the effects on the domain or check controller properties to verify messages or objects prepared for rendering. All subclasses of SmartDispatcherController have a public Context property that allows us to inspect the Rails engine context as well.
There is just one slight problem with the BaseControllerTest. All its interesting methods are protected, so the test class has to subclass BaseControllerTest. It would be ideal to reuse the unit testing support for the data access layer that we developed in the first article, but C# does not support multiple inheritance. A workaround for that is to extend BaseControllerTest once, expose appropriate methods as public, and then embed that into another test class that initialises the data access system. Here is MRTestBase class that provides all the functionality of ARTestBase and also allows us to initialise controllers for testing:
using EvilLink.Database.Test; using Castle.MonoRail.TestSupport; using Castle.MonoRail.Framework; namespace EvilLink.Controllers.Test { public class ConcreteControllerTest:BaseControllerTest{ // just expose PrepareController as a public method public void InitController(Controller controller) { PrepareController(controller); } } public class MRTestBase:ARTestBase { private ConcreteControllerTest context = new ConcreteControllerTest(); // expose InitController public void InitController(Controller controller) { context.InitController(controller); } } }
We can use a dummy implementation of the user context, not tied to the real HttpSession object, to verify the session storage (this would be a good place to use a mock factory).
using EvilLink.Database; namespace EvilLink.Controllers.Test { public class DummyUserContext:IUserContext { private int? currentuserid; public int? CurrentUserId { get { return currentuserid; } set { currentuserid = value; } } public User CurrentUser { get { return currentuserid == null ? null : User.Find(currentuserid); } } } }
Writing NUnit tests
We can now write a couple of unit tests inspecting the workflow and session behaviour of the user operations controller. In the setup, we initialise context objects, create a user to play with and prepare the controller. Notice that we just call the constructor and then pass the object to PrepareController and that is it — no black magic involved. We can call the login method and then inspect the user context to check whether the expected user object was stored in the session. We can also try to log in with an incorrect password and verify the message coming out (hint: PropertyBag is a public property of the controller, so we can inspect it directly). The SelectedViewName property will give us a way to check which view was selected for rendering. We can verify that the controller initiated redirection by checking Context.Response.WasRedirected property, but I don’t know of a good way to verify redirection URL at the moment. Jimmy Bogard explored some options for that like changing the redirect method. Apart from that, we can easily test everything else:
using EvilLink.Database.Test; using NUnit.Framework; using EvilLink.Database; using Castle.MonoRail.TestSupport; namespace EvilLink.Controllers.Test { [TestFixture] public class TestUserOps:MRTestBase { DummyUserContext wuc; UserOpsController ops; User mike; [SetUp] public override void SetUp() { base.SetUp(); wuc = new DummyUserContext(); ops = new UserOpsController(wuc); InitController(ops); mike = new User("mike", "mike", "mpass", "m@m.com"); mike.SaveAndFlush(); } [Test] public void TestLogin() { ops.Login("mike", "mpass", "/home"); Assert.AreEqual(mike, wuc.CurrentUser); } [Test] public void TestLoginIncorrectPassword() { ops.Login("mike", "wrongpass", "/home"); Assert.AreEqual(null, wuc.CurrentUser); Assert.AreEqual("Username or password incorrect, please try again", ops.PropertyBag["error"]); Assert.AreEqual(ops.Name+"\\index", ops.SelectedViewName); Assert.AreEqual("/home", ops.PropertyBag["goBackUrl"]); } [Test] public void TestRegisterUser() { ops.SubmitRegistration( new User("tom", "tsmith", "tpass", "t@t.com")); Assert.AreEqual( "You have registered successfully. You can now log in.", ops.Context.Flash["message"]); Assert.AreEqual(true, ops.Context.Response.WasRedirected); User u=User.FindAllByProperty("Username", "tsmith")[0]; Assert.AreEqual("tom", u.Name); Assert.AreEqual("t@t.com", u.Email); } } }
Build the project, fire up your NUnit test runner, and you should see the tests pass:

Some links for the end
- Source code for this iteration
- More detailed information about BaseControllerTest
- Older library for testing, that works by simulating complete http requests and responses.
Stuff to remember
- BaseControllerTest class from Castle.Monorail.TestSupport provides a framework to unit test controllers.
- Just create the controller as any other object and pass it to the PrepareController method of BaseControllerTest to be able to call its methods directly
- SmartDispatcherController exposes almost everything interesting to verify as public properties, including SelectedView, PropertyBag and Context.
Next exercise
In the next article of this tutorial, we look into injecting services and configuration into controllers using the Windsor dependency injection framework. That article should be online soon. (Subscribe to RSS updates to get notified about that). As I mentioned above, if you are in UK, come to the free session on developing Ajax applications with Monorail that will take place on Thursday 12th to learn more about what Castle can do for you.
![]() |
![]() |


