Getting ready for PrairieDevCon
Next week I’ll be presenting at the PrairieDevCon
in Regina and one of my presentations is about Behavior Driven Development, how to apply it using .NET tools like SpecFlow, Nunit, Watin, Cassini, MbUnit, etc.
Because is a Dojo/Code with me presentation I’m planning to do a BDD exercise with all the attendees to show them how to describe a new feature using BDD and implement it together.
We will start with a project that has one feature implemented, and will code together the second feature using full BDD and TDD.
So, what should I use to illustrate BDD? No other than my old friend the MediaLibrary example that I used quite a few times, but now including a full BDD implementation.
The MediaLibrary project is a web application that allows the user to register and catalog his collection of movies, books, games, etc.
I’m using GitHub to publish the code we are going to use in the Dojo. Right now the latest version represents the code that I’m going to start with.
If you would like to check out the code I’m going to use please go to the PrairieDevCon page
on my blog and get the code from GitHub
, read the README file to verify you have the requirements installed and the application is working.
Do you have everything installed? Did you read the README file? Cool, open the solution and let’s move on!
Behavior Driven Development is a term used to describe (in our case) development that starts by writing the feature (or user story) that we want to implement. Once we have the feature, we will use a “story runner” that will run the feature we just wrote and show if the story is actually implemented as we wanted or not yet. If it is, good, everything should be “green”. If not, we get a “red”, and we have to add code and implement more functionality to make it pass.
To write the user story we are going to use a particular syntax from the Gherkin language. The Gherkin language has very few rules, please read the introduction for Cucumber from Aslak Hellesoy
Let’s see the feature that it’s implemented in the code, Browse Movies:
Feature: Browse Movies
As a User
I want to Browse Movies
So I can see the contents of the library
Scenario: Browse available movies
Given I have the following movies:
| title |
| Blazing Saddles |
| Space Balls |
When I go to Movies
Then I should see in the listing:
| title |
| Blazing Saddles |
| Space Balls |
What is most important here is to look at the scenario. The scenario is describing that if you have movies A, B and C in the library, when you browse you should see the same movies on the Movies
Now if we want to check the feature manually, what would we do? Something like this:
- Add the movies to the storage
- Start the web application
- Launch the browser
- Go to the movies page
- Check that all the movies in the storage are listed in the browser
The thing is that I don’t want to validate each feature (with many scenarios) manually, I’d like the scenario/feature runner to do that for me, add the movies, launch the browser and check, everything automated following the steps I wrote in my scenario.
Probable we could manage to write code that will do that for us, now, the question is how the scenario runner translates this feature into actual code? If we were using rails we could use Cucumber,
but luckily for the .NET world we can use SpecFlow
too, but that’s another post).
Given That I have the following movies
Specflow is a tool that understands Gherkin
and generates an NUnit
test for every feature that we use. Being an NUnit test, simplifies how we going to run the specification. Just run the NUnit test with your favorite test runner: ReSharper
, NUnit (console or GUI), MbUnit
Each scenario is composed by a series of steps, each step is identified by a Gherkin keyword, in our feature we found Given, When
The NUnit test has code for each scenario and will invoke the steps indicated in the scenario.
In order to do so, Specflow uses the text that we write in the step, to match the code.
Let’s look at our first step “Given I have the following movies:”. In order to implement the step, in the code, you will find a method that looks like:
[Given(@"I have the following movies:")]
public void AddMovies(Table movies)
movies.Rows.ForEach(row => AddMovieToStorage(row["title"]));
attribute is used to match the text we wrote in the scenario, to indicate the the method AddMovies
should be called when the step is invoked.
The step in the scenario indicates that the method receives a series of rows should be passed as parameter (first row is the title, every column separated by “|”), that is why it receives a Table
In the implementation for each movie in the table, the title will be added to the storage. Check the method AddMoviesToStorage
for more details.
Now that we setup our storage we are ready to move on and launch the browser.
When I go to Movies
The next step to implement implies opening the browser and going to the Movies
page to see the listing.
Now, to do so we need two things, first the web application running and then to launch a browser to go the actual page.
To run the application I’m going to use Cassini
web server. The setup of the features will start the web server and stop it when it’s not needed any more. We can see the implementation in the Browser
class under Utililty.
WebServer = new Server(Port, "/", GetPhysicalPath());
With the server running, we now need to launch the browser and automate the checking for all the movies.
For that we are going to use
(Web automation test in .NET) is a library that helps us to manipulate the browser (based on Watir
) and also give us all the HTML for the page we are visiting.
We can see the use of the IE
instance in the Browser
public static void InitializeBrowser()
Instance = new IE(ApplicationURL);
public static void ShutdownBrowser()
Now that we have our server running, and our IE
instance, we only need to go to the right path. In this case we want to go to “/Movies”. For that let’s look at the NavigationSteps class:
[When(@"I go to (.*)")]
public void WhenIGoToPage(string pageName)
The step uses the browser to navigate to the right page. The page is passed as a parameter that we can see in the attribute as a regular expression.
So far, so good. Now, our last step is to check for the movies in the page to make sure that all of them are in the list.
Then I should see in the listing
To implement the last step in our scenario we are going to use the following implementation:
[Then(@"I should see in the listing:")]
public void AssertListingContains(Table movies)
var expected = movies.Rows.Select(row => row["title"]);
var listing = this.Page.Listing;
Again we are using a step that takes a table as parameter, so we iterate thru the table and get the titles of all the movies that should be in the page.
The code has no mysteries except the Page
this.Page = new BrowseMoviesPage();
property is initialized in the constructor and the goal of the BrowseMoviesPage
is to abstract the internals of how the movies are listed in the page. For example, right now the view that implements the listing of movies uses a table for each movie, however it could use a DIV
or some other tag. Here is the implementation:
public IEnumerable<string> Listing
var elements = Browser.Instance.TableCells.Where(cell => cell.ClassName == "title");
return elements.Select(e => e.InnerHtml.Trim());
As we can see, the code is getting all the table cells where the CSS
class is title
and then getting the inner html and trimming it.
If we would have to use this code every time we want to check the listing we would have code duplication, plus if the implementation of the view changes, we would have to modify each piece of code that refers to this page. Using the PageObject
pattern we avoid code duplication and it’s easy to change the implementation.
And voila! We got all our steps implemented.
If you join me next week on the Prairie Dev Con, we will implement the next feature together “Add Movies”.
What’s so cool about BDD? Please go ahead and run “rake test:features” on the command line, and you’ll see that the steps for the second feature are still pending, that means that they are not implemented yet.
Writing the feature first we manage to describe what we want, and implementing step by step we make sure that we are working towards make the feature pass. BDD on the outside and TDD on the inside.
Hope to see you all next week in the conference!