Tuesday, 01 November 2011
Eating the Agile BDD Cake with SpecFlow - Part 2

In the previous part of this article I took you through how I would go through testing using Agile and BDD together in one process from the start to finish in a test project. In the previous article we had setup our project and our story/feature for viewing our basket and getting the tests to run and fail. Next we will code the basket to get the tests to pass.

So in my solution I have 3 projects.

image

I have my Domain, most of this is going to be encapsulated by my Model. The web is where I have my model, view and controller, and yes I probably would split the model out from the web project. Lastly we have the tests project where all of our features live.

On to the code.

So my test will be hooking into my Basket Model. My BasketModel consumes an IBasketRespository type for which I do not have an implementation of. The reason being, I am not doing an integration test so I don't really care what is in this object and will mock it using Rhino Mocks in my test.

   1:  using DemoBDD.Domain.Contracts;
   2:   
   3:  namespace DemoBDD.Web.Models
   4:  {
   5:      public class BasketModel
   6:      {
   7:          private readonly IBasketRespository _basketRespository;
   8:   
   9:          public BasketModel(IBasketRespository basketRespository)
  10:          {
  11:              _basketRespository = basketRespository;
  12:          }
  13:   
  14:          public BasketFormModel GetBasket(string basketId)
  15:          {
  16:              return Mappers.MapBasketDomainToBasketFormModel.MapBasket(_basketRespository.GetBasketByBasketId(basketId));
  17:          }
  18:      }
  19:   
  20:   
  21:  }

And now my test

   1:  namespace DemoBDD.Web.Tests.StepDefinitions
   2:  {
   3:      [Binding]
   4:      public class ViewBasketItemsSteps
   5:      {
   6:          private BasketModel _basketModel;
   7:          private IBasketRespository _mockbasketRespository;
   8:          private BasketFormModel _basket;
   9:          private string _basketId = "fakebasketid";
  10:   
  11:          [Given(@"that the shopping basket contains 0 items")]
  12:          public void GivenThatTheShoppingBasketContains0Items()
  13:          {
  14:              var mock = new MockRepository();
  15:             
  16:   
  17:              _mockbasketRespository= mock.StrictMultiMock<IBasketRespository>();
  18:   
  19:              Expect.Call(_mockbasketRespository.GetBasketByBasketId(_basketId)).Return(new Basket(){Items = new List<BasketItem>()});
  20:   
  21:              mock.ReplayAll();
  22:   
  23:              _basketModel = new BasketModel(_mockbasketRespository);
  24:          }
  25:   
  26:          [When(@"I view the basket")]
  27:          public void WhenIViewTheBasket()
  28:          {
  29:              _basket = _basketModel.GetBasket(_basketId);
  30:              Assert.IsNotNull(_basket);
  31:          }
  32:   
  33:          [Then(@"the basket will show an empty basket")]
  34:          public void ThenTheBasketWillShowAnEmptyBasket()
  35:          {
  36:              Assert.AreEqual(_basket.Items.Count,0);
  37:          }
  38:   
  39:   
  40:      }
  41:  }

And the results of my test.and it all worked first time.surprising Smile

image

.What next?

I think I like SpecFlow, I think I am liking it more than MSpec and I never thought I would find myself saying that.

But I find what I have done has still left me with many questions and I can start to think of all kinds of ways to refactor what I have done which is natural for any developer and tests or "specifications" help us make sure that what we are changing is still working once it has been changed.

So what would I change?

  1. I would probably move the tests to the controller and not the Model. Why? Because BDD is supposed to be a top down development approach. Work at the top and work your way down. Testing my controller is also going to test my Model for me in this case.
  2. If my project grew larger I may move the model into a separate project.

Unsure of

  1. Adding integration tests later on to cover the repository layer. Would these connect back to the same story/feature? Or would we have a different story or feature that covered this aspect?
  2. Bug fixing. Would we create features for bugs or would we update an existing feature to take the bug into account?
  3. Having been to a session on BDD I found it interesting how one team had thrown out tasks and completely replaced them with scenario's. In a way it makes sense and I would be intrigued to try this concept out for myself.
posted on Tuesday, 01 November 2011 09:41:45 (GMT Standard Time, UTC+00:00)  #    Comments [0]