Unit testing MonoRail controllers
I spent yesterday finishing off (mostly) my business model, then the end of yesterday + today writing test cases for those classes. Everything was going great, I found at least 3 errors in my code that I hadn’t realised was there and also realised there were a few more things I needed.
Then it was time to start testing the controllers in my MonoRail site. What a disaster!
Attempt 1:
The problem with this was pretty obvious, Controller doesn’t have a Response etc set up. So along came attempt 2:
Now the controller is set up with mock objects and will run! Unfortunately the BeforeAction filter on my action was not being executed. Aha! Pretty obvious problem! If I call the method directly how can the framework possible find all of the reflection attributes and process them etc? *slaps head*
Attempt 3
Still no joy! The filters just aren’t being executed. Someone on the user groups said that this is expected behaviour and that the filter should be tested in isolation. Whereas I agree for the most part unfortunately it doesn’t apply in this case. My ECO extensions to MonoRail allow the developer to specify pooling, session, default EcoSpace types, and so on. If these reflection attributes aren’t processed then the action just isn’t going to act in the same way it will at runtime!
At the moment I am sorely disappointed! I was really looking forward to writing a test driven website but unless this guy was wrong it doesn’t look like it is going to be possible!
It’s at times like these I wonder how difficult it really is to write your own MVC framework? Maybe I will take another look at the MS offering. If I had enough free time I'd make my own :-)
Then it was time to start testing the controllers in my MonoRail site. What a disaster!
Attempt 1:
[Test]
public void AdminOnly_Home()
{
AdminController controller = new AdminController();
controller.Home();
Assert.IsTrue(Controller.Response.WasRedirected, "Should have been redirected");
}
The problem with this was pretty obvious, Controller doesn’t have a Response etc set up. So along came attempt 2:
[Test]
public void AdminOnly_Home()
{
AdminController controller = new AdminController();
PrepareController(controller);
controller.Home();
Assert.IsTrue(Controller.Response.WasRedirected, "Should have been redirected");
}
Now the controller is set up with mock objects and will run! Unfortunately the BeforeAction filter on my action was not being executed. Aha! Pretty obvious problem! If I call the method directly how can the framework possible find all of the reflection attributes and process them etc? *slaps head*
Attempt 3
[Test]
public void AdminOnly_Home()
{
AdminController controller = new AdminController();
PrepareController(controller, "Admin", "Home");
controller.Process(Controller.Context, Controller.ControllerContext);
Assert.IsTrue(Controller.Response.WasRedirected, "Should have been redirected");
}
Still no joy! The filters just aren’t being executed. Someone on the user groups said that this is expected behaviour and that the filter should be tested in isolation. Whereas I agree for the most part unfortunately it doesn’t apply in this case. My ECO extensions to MonoRail allow the developer to specify pooling, session, default EcoSpace types, and so on. If these reflection attributes aren’t processed then the action just isn’t going to act in the same way it will at runtime!
At the moment I am sorely disappointed! I was really looking forward to writing a test driven website but unless this guy was wrong it doesn’t look like it is going to be possible!
It’s at times like these I wonder how difficult it really is to write your own MVC framework? Maybe I will take another look at the MS offering. If I had enough free time I'd make my own :-)
Comments
This is related to ASP.NET MVC, but the idea is to have ControllerTester class.
It inherits in your unit test project and overrides some methods to provide more information for the unit tests.
You don't have to mock everything. Some things can be done with a poor OO approach.