Incremental development with Monorail
EDIT: This is hosted in a google code project accessible from here: http://code.google.com/p/mr-blogengine/
This is the first of a series of posts I’m penning where I’ll be incrementally developing a basic blog engine running on the Castle trunk and developed wholly test first.
Each new feature or addition will be described by simple narrative, followed by some testing/coding from the UI (or controller in this case) down to the database.
I’ll be using much of the Castle stack goodness including Monorail, Windsor and ActiveRecord. Unit testing with Mbunit and acceptance testing with Watin.
My aim with this series of posts is to demonstrate the power of the Castle stack, combined with TDD and the slow, incremental addition of features. After each post I’ll check in my latest changes which will after a clean build will result in a fully working system.
I’ve completed a small amount of scaffolding up-front for brevity:
- Castle built from trunk
- Solution and project structure
- Basic configuration of Monorail and Windsor
As you can see from the right, our solution consists of three projects. The core project will hold our domain model, interfaces, services and application code. There is a test project for both our unit tests and acceptance tests, and finally we have the web application project holding our controllers, views and static content. I’ve put together a basic layout and stylesheet that serve our needs for now. This will be added to as our blog engine matures.
Although we have no concrete examples as yet, the controllers, services, facilities and configuration properties are configured through Windsor XML configuration files in the web project. We’re running on a Castle build I ran locally after checking out the trunk some point over the last couple of days.
It will be interesting to see how our initial design adapts as required when features are piled on during the later stages of development. I’ve not got any specific plans on how long this series will go on for although I am considering moving my blog away from WordPress and will most likely host under the very blog engine I’ll be creating. Good times! Anyway enough of this, lets move on to the first iteration.
Iteration 1: Create a Post
For this iteration we will build our first cut at the blog post authoring screen. This comprises a very basic form allowing the author to specify the title, short description and full content of the post. I think you’ll agree that what we’re building in this iteration won’t serve as a fully powered blog engine any time soon, but lets restate our initial aim here: to incrementally build and adapt our system as new requirements and features emerge. With that said, lets get on to building our first feature!
Our first test:
From our basic requirement we’re now driving out the PostController. This test simply gets our controller into a good state for testing, handily provided by Monorail’s BaseControllerTest and our first test method asserts that when the Add action is called on our controller the correct view is rendered. As you can see from the grab above there is a lot of red code. Resharper is highlighting the members we’ve yet to implement. I attempted to run this test but the compiler chokes. Time to do what we need to pass this test:
Well that was simple enough. Lets run our test and see the result:
As expected, the test now passes. However, there are some serious issues with our controller and the related Monorail configuration:
- The controller has no associated layout.
- We’ve yet to create the requisite view: Add.vm.
- We’ve not added the Windsor XML configuration for our controller.
Before we can do anything to remedy the issues above we’ll need to write a failing test. I’m going to use Watin to create a test which flexes Monorail a little more. Currently our only test relies heavily on most of the controller dependencies being stubbed/mocked out by the BaseControllerTest class. We’ll need to test through the browser to ensure our controller and view/layout are wired up correctly:
As you can see above we’ve crafted a very simplistic test which asserts that the text “Ben Lovell’s Blog” is found in the browser at the specified URL. Note also that our test assumes the application is running at localhost on port 16489. I’ve configured this in the web application properties so we just need to ensure that the VSNET web development server is running on this port for our application. Lets run the test:
As expected it fails. To pass this test we need to perform the three steps mentioned earlier. To do this we first add the Layout attribute to the controller and specify the default layout, the contents of which are shown here:
Next we create an empty view: Add.vm in the views/post folder, and finally we wire up the XML configuration for our controller in the controllers.config file as shown below:
Lets try and run the test now:
Now we’re making progress! Lets extend our test a little more now. This time we will find the title, description and content fields, enter some values and submit the form. Asserting that the confirmation message was displayed telling the user their post was saved:
A few things have changed here: we’ve altered the naming of the test to clarify intent, and as mentioned previously our test will enter some values into our form fields and submit the form. Our last assertion is checking that the correct confirmation message is displayed. Now we could argue that the setting of the description and content is superfluous in this test as the outcomes aren’t asserted. But, the effort required to implement those fields is minimal and highly unlikely to impact on any existing code/tests (i.e. none!).
Lets run the test and see the outcome:
Our test complains that the “Add Post” text was not found. Lets go and fiddle with our view:
Good to go, lets run the test:
Hmm, the first two asserts are passing but now we’re failing on unfound input: post.Title. Time to add the form and fields to the view, we’re going to make a slight jump and include the description and content inputs in our view also:
Re run the test:
It fails as we have yet to create the save action on the controller, and also the nonexistent action doesn’t display the required confirmation… For obvious reasons.
At this stage I’m going to wrap this up for now. Part two will follow over the next couple of days. Stay tuned!