domingo, 30 de noviembre de 2008

Cucumber vs StoryRunner

Hi guys!,

I'm exploring the capabilities provided by this beautiful framework, as It is going to be used by our team at work. So I decided, to take advantage of that, and study it a little deeper and share with you which my impressions are.

Installation

This is just typing:

gem install cucumber

And to install in your Rails project, execute this line on your vendor/plugins directory:

git clone git://github.com/aslakhellesoy/cucumber.git

Features

So the first important difference to notice is that Cucumber is about features (not .stories). The idea behind this is to write the old stories in a more BDD way. So, for each new feature that you have to develop, you should first write a file on the features folder (and with .feature extension), and specify the new functionality on it, in such a way it would fail. When the feature is fully implemented, the test should be successful.

You can execute a cucumber features like this:

* cucumber features/my_new_feature.feature or by executing:

* rake features if you configure the Rakefile of you application with the following code:

require 'cucumber/rake/task'
Cucumber::Rake::Task.new


Contents of features files

Cucumber is about Features (instead of StoryRunner's Stories). Inside a Feature, in a similar fashion as StoryRunner, we got to define an Scenario. So one of the first lines of that file should be an Scenario with a key that identifies it. Then every Scenario is composed by a list of one of those keywords: Given, Then, When (same as StoryRunner) AND But.

Here is a simple example of a Cucumber's feature:

Feature: Serve coffee
In order to earn money
Customers should be able to
buy coffee at all times

Scenario: Buy last coffee
Given there are 1 coffees left in the machine
And I have deposited 1$
When I press the coffee button
Then I should be served a coffee


The definition of what to do within each step (a Given, Then, When or But sentence) is loaded from steps's files in a similar way StoryRunner does. But, Cucumber have an important difference here: they are written using Regular Expressions instead of strings. So you can do something like this:

When /(\w+) enters (his|her) email with "(\S+\@\S+)"/ do |name, email|
fills_in field_name, :with => User.find_by_name(name).email
end


As you can see, using Regular Expressions give us more expressiveness while writing our features.

Until this point, every seems pretty much the same as StoryRunner, but I found a big improvement here:

1) Steps are automatically available from step_definitions (or any sub-folder of features) folder. This is a big difference for reutilization compared with StoryRunner which requires to import explicitly any step's files needed by the story.

2) There's a relatively new feature which let's you invoke steps from within other steps. For example, we can have some common steps like: /Given a user with login '(\S+)'/, /And is not logged in/, among others that can be reused in many features (we probably need our user logged in to use most of our site functionality). Then each we can invoke this steps within other steps, like this:

#features/steps/login_steps.rb
Given /a user with login '(\S+)'/ do
..
end
Given /a password '(\S+)'/ do
..
end
Given /is not logged in/ do
..
end

#features/steps/somefile_steps.rb
Given /User (\S+) with password (\S+) is logged in/ do |username, pass|
Given "a user with login #{username}"
Given "a password #{pass}"
Given is not logged in
end

#features
Feature: Some feature

Scenario: Some scenario description

Given User pepe with password pepe is logged in
And ..
Then ..

This way, we can reuse most of our steps, making our test more DRY.

3) Finally, it is possible to define our stories in a different language than English. But as I won't be using this for now, I didn't realize how interesting this might be..as most of my work is written in English, but you never know :P.

That's enough for now, talk to you later ;)