Saturday, October 24, 2009

An AAA style BDD specification base class

Lately I have written a lot of Arrange, Act, Assert style tests using Rhino Mocks. I’ve also started to write more readable tests with a dash of BDD style naming like this:

[Fact]
public void Should_find_projects_when_user_searches()
{
 //Arrange
 var projectRepository = MockRepository.GenerateMock<IProjectRepository>();
 var projects = new List<Project> { ProjectMother.CreateProject("project 1"), ProjectMother.CreateProject("project 2") };
 projectRepository.Stub(me => me.FindByName(null)).IgnoreArguments().Return(projects);
 var presentationModel = new ProjectSearchPresentationModel(projectRepository);
 //Act
 presentationModel.SearchCommand.Execute("");
 //Assert
 projectRepository.AssertWasCalled(me => me.FindByName(""));
 Assert.Equal(projects.Count, presentationModel.Projects.Count);
}

The scenario for this test is “When the user searches”. If we look closely we see that it have two asserts. When the user searches it should ask the repository for projects and the result should be “displayed” in a list. This feels a bit odd. I have to create a name for the test that captures everything that has to be done when the user searches. This is hard and I’m likely to loose some of the intent. The solution is to split the test in a test for every assert. However, this means that I have to set up each test in an equal manner and call the serach command. This is DRY! To solve this I’ve created a test base class called Specification that enables me to write the above test like this:

namespace Specifications_for_project_search_presentation_model
{
 public class When_user_searches_for_projects : Specification
 {
     private ProjectSearchPresentationModel _presentationModel;
     private List<Project> _projects;
     private IProjectRepository _projectRepository;

     public override void Arrange()
     {
         _projectRepository = MockRepository.GenerateMock<IProjectRepository>();
         _projects = new List<Project> { ProjectMother.CreateProject("project 1"), ProjectMother.CreateProject("project 2") };
         _projectRepository.Stub(me => me.FindByName(null)).IgnoreArguments().Return(_projects);
         _presentationModel = new ProjectSearchPresentationModel(_projectRepository);
     }

     public override void Act()
     {
         _presentationModel.SearchCommand.Execute("");         
     }

     [Fact]
     public void should_search_repository()
     {
         _projectRepository.AssertWasCalled(me => me.FindByName(""));         
     }

     [Fact]
     public void should_show_result()
     {
         Assert.True(_presentationModel.CanShowProjects);
     }

     [Fact]
     public void should_list_projects_found()
     {
         Assert.Equal(_projects.Count, _presentationModel.Projects.Count);
     }
 }
}

I have now set up the context and called the search command only once, but have a seperate test for each assert. I think these kind of tests read nicely. I have a test class for each scenario and tests that reads like the specification for the scenario. This also look very good in ReSharper.

specifications

The base class is implemented like this for xUnit:

public abstract class Specification
{
 protected Specification()
 {
     Arrange();
     Act();
 }

 public abstract void Arrange();
 public abstract void Act();
}

3 comments: