Building a MVC2 Template, Part 4, BDD with MSpec

1 Comment

This post will cover installing TestDriven.Net (TD.Net), NUnit, and  Machine.Specifications (MSpec). There are plenty of resources on the internet for installing all of these applications.  I don’t want to duplicate the content of those posts, but I am including this post for completeness.

If you read any of the Behavior Driven Development posts on the net you’ll read where the tests should be written first. Since the MVC2 project auto-generates the code with a handful of tests, we’ll convert them to MSPec specificatoins now so we don’t get behind on writing our spec.

If you have been following this series, you’ll wonder if you missed any steps after installing these three applications.  The install process is so simple and straight forward there is no need for any screen shots.

Installing NUnit

The latest version of NUnit at the time of this post is 2.5.3, and can be downloaded from http://www.nunit.org. Run the install and you can accept all of the defaults. I choose to install the complete setup.

Installing TestDriven.Net

Download the latest version of TestDriven.Net from http://www.testdriven.net/. Make sure you have exited all instances of Visual Studio prior to running the setup. Choose the defaults all the way through the setup.

Installing MSpec

You can either download the source code from http://github.com/machine/machine.specifications, or download the latest successful TeamCity build at http://teamcity.codebetter.com/guestAuth/repository/download/bt44/.lastSuccessful/Machine.Specifications-release.zip.

I downloaded the latest build and extracted to the folder C:\_CodeVault\MSpec. Since we are using TD.Net as our test runner, double click the InstallTDNetRunner.bat. This will set a few registry settings that configures TD.Net to run MSpec.

MSpec-External-Tool
Next open Visual Studio and navigate to Tools/”External Tools”. Click Add to add a new tool to the Tools menu. Use these options:

Command: C:\_CodeVault\MSpec\mspec.exe
Arguments: $(TargetName)$(TargetExt) –html “$(ProjectDir)\Report.html”
Initial Directory: $(BinDir)

Make sure you check the “Use Output window” checkbox. These options will put the output HTML file into your project folder.

Writing Tests or Specifications

Ok, lets fire up Visual Studio and open our Nehemiah solution. Execute these steps on the Nehemiah.Specs project:

  1. Add a reference to the Machine.Specifications.dll stored in C:\_CodeVault\MSpec.
  2. Add a reference to NUnit.Framework.dll stored in C:\Program Files\NUnit 2.5.3\bin\net-2.0\framework.
  3. In the Controllers folder, rename HomeControllerTest.cs to HomeControllerSpecs.cs.
  4. In the Controllers folder, rename AccountControllerTest.cs to AccountControllerSpecs.cs.

Now we will convert the existing tests into specs. The MVC2 template generates two actions and two views for the HomeController, Index and About. Here is the code for HomeControllerSpecs. You can either save the existing code to another file or simply comment out the code. For brevity, the existing tests are not shown, just the replacement specs.

using Machine.Specifications;

namespace Nehemiah.Specs.Controllers
{

[Subject("Home Page")]
public class when_the_home_page_is_requested
{
It should_return_the_home_page;
}

[Subject("About Page")]
public class when_the_about_page_is_requested
{
It should_return_the_about_page;
}

}

Next we’ll convert the AccountController tests to specs.

using System;
using System.Security.Principal;
using System.Web;
using Machine.Specifications;

namespace Nehemiah.Specs.Controllers
{

[Subject("Account Actions")]
public class when_the_change_password_page_is_requested
{
It should_return_the_change_password_page;
}

[Subject("Account Actions")]
public class change_password_returns_change_password_success_page_on_success
{
It should_return_a_RedirectToRouteResult;
It should_return_the_change_password_success_page;
}

[Subject("Account Actions")]
public class change_password_returns_change_password_page_on_failure
{
It should_return_the_change_password_page;
It should_include_a_change_password_failure_message;
It should_include_a_value_for_a_minimum_password_length;
}

[Subject("Account Actions")]
public class change_password_returns_change_password_page_on_data_validation_errors
{
It should_return_the_change_password_page;
It should_include_previous_form_data_with_validation_errors;
It should_include_a_value_for_a_minimum_password_length;
}

[Subject("Account Actions")]
public class change_password_returns_password_changed_page_on_success
{
It should_return_the_password_change_page;
}

[Subject("Account Actions")]
public class log_off_will_log_out_the_user_and_return_the_home_page
{
It should_log_out_the_user;
It should_return_a_RedirectToRouteResult;
It should_return_the_home_page;
}

[Subject("Account Actions")]
public class when_the_logon_page_is_requested
{
It should_return_the_logon_page;
}

[Subject("Account Actions")]
public class log_on_returns_redirect_on_success_without_a_return_url
{
It should_log_in_the_user;
It should_return_a_RedirectToRouteResult;
It should_return_the_home_page;
}

[Subject("Account Actions")]
public class log_on_returns_redirect_on_success_with_a_return_url
{
It should_log_in_the_user;
It should_return_a_RedirectToRouteResult;
It should_return_the_requested_url;
}

[Subject("Account Actions")]
public class log_on_returns_log_on_page_on_data_validation_errors
{
It should_return_the_logon_page;
It should_include_previous_form_data_with_validation_errors;
}

[Subject("Account Actions")]
public class log_on_returns_log_on_page_on_log_in_failure
{
It should_return_the_logon_page;
It should_include_previous_form_data;
It should_include_a_validation_error_message;
}

[Subject("Account Actions")]
public class when_the_registration_page_is_requested
{
It should_return_the_registration_page;
}

[Subject("Account Actions")]
public class registration_page_returns_user_to_home_page_on_success
{
It should_return_a_RedirectToRouteResult;
It should_return_the_home_page;
}

[Subject("Account Actions")]
public class registration_page_returns_registration_page_if_registration_fails
{
It should_return_the_registration_page;
It should_include_previous_form_data;
It should_include_a_validation_error_message;
It should_include_a_value_for_a_minimum_password_length;
}

[Subject("Account Actions")]
public class registration_page_returns_registration_page_on_validation_errors
{
It should_return_the_registration_page;
It should_include_previous_form_data_with_validation_errors;
It should_include_a_value_for_a_minimum_password_length;
}

}

SolutionExplorer01
Now rebuild the solution. Highlight the Nehemiah.Spec project. Then run the MSpec external tool from the Tools menu. You should now have a file named Report.html in the Nehemiah.Specs folder.  Open the file.

Report-html
Your file should like similar to the screen shot above.

We need to update our project file again. So unload the Nehemiah.Specs project. Then edit the Nehemiah.Specs.csproj file. Locate the HintPath for Machine.Specifications.dll.  It will be a relative path to the DLL.  This would be fine if we had created a folder in our project to hold the DLLs. Modify it to read C:\_CodeVault\MSpec\Machine.Specifications.dll. Save the file and reload the project.  If you don’t modify the project file the TeamCity build will fail as it will not be able to locate the dll.

Commit your changes to Subversion.

In a few minutes TeamCity should recognize you’ve checked in some changes. Then it will rebuild your project. It should rebuild successfully.

In the next post we’ll flesh out these tests.

References

Shout it


Kick It on DotNetKicks.com
Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

One Comment (+add yours?)

Leave a Reply

Comment moderation is enabled. Your comment may take some time to appear.