This post will be part of a series about developing my sample application (Sell and Buy).
Starting from very initial documentation describing Ubiquitous Language and User Stories.
As described in Wikipedia, BDD encourages collaboration between team members and business stakeholders. It describes a cycle of interactions with well-defined outputs, resulting in the delivery of working, tested software that matters. Behavior-driven developers use their native language in combination with the ubiquitous language of domain driven design to describe the purpose and benefit of their code.
Recently I’ve played with SpecFlow, and found it very appealing in defining behaviors specially end-to-end tests. So I started my solution by creating a SpecFlow project taking the first user story and apply it then start to build the walking skeleton.
It is not very much walking skeleton, as I had to invest a little more time designing the infrastructure and basic layers of the applications.
Story 1.1: List recent ads
As a buyer, I want to find recent ads, so that I can find something interesting.
This very first user story states that when a user first open homepage, he should see a list of recent ads. The following is the implementation using SpecFlow:
A feature in SpecFlow is mapped to a user story using the same syntax of user story.
A Background describes the givens, it is very beneficial here because in this user story, we assume that there are already definitions in the system. We assume that there is a customer (seller), a category (Books), some available conditions for the ad type, some items definitions, and finally a list of ads published.
Each feature in SpecFlow is mapped to Steps definition file which is a class bound to the feature with methods bound to elements in the feature to execute it.
for example “Given the following customers” will be mapped to a method with Table as parameter filled with customers in the feature.
[Given(@"the follwing customers")]
public void GivenTheFollwingCustomers(Table table)
{
var customers = new List<Customer>();
foreach (var tableRow in table.Rows)
{
var customer = new Customer
{
FirstName = tableRow["First Name"],
LastName = tableRow["Last Name"],
Email = tableRow["Email"]
};
customers.Add(customer);
}
GetCustomerRepository().Add(customers);
GetCustomerRepository().UnitOfWork.Commit();
}
The first scenario starts with the condition “When I enter homepage” would be mapped to:
[When(@"I enter home page")]
public void WhenIEnterHomePage()
{
var AdService = GetAdService();
var controller = new HomeController(AdService);
_actionResult = controller.Index(null, null);
}
This code instantiates a new ASP.Net MVC HomeController passing it AdService instance and calling Index method which will return ActionResult.
Then comes the expectation “Then the home page shows ads …” which is mapped to:
[Then(@"the home page shows ads")]
public void ThenTheHomePageShowsAds(Table table)
{
var adsViewModel = _actionResult.Model();
foreach (TableRow row in table.Rows)
{
CustomAssert.Any(adsViewModel.PageItems,
a =>
a.Item.Name == row["Title"] &&
a.Description == row["Description"] &&
a.Price == Decimal.Parse(row["Price"])&&
a.Customer.FirstName == row["Customer First Name"]&&
a.Customer.LastName == row["Customer Last Name"]);
}
Assert.AreEqual(table.Rows.Count(), adsViewModel.PageItems.Count(), "The list contains other ads too");
}
This code gets the view model from the actionresult and assert that it includes expected fields.
This very first user story started to give us an idea of end to end test, at this stage we are in the phase of creating the walking skeleton which will include infrastructure layers and domain entities, persistence, services … In later posts we will discuss the rest of implementation.
