BDD with Cucumber and Ruby: fast intro for impatient developers

Testing

Cucumber is a very fun and cool tool for writing automated acceptance tests to support software development in the behavior-driven development (BDD) style.

Getting ready

In the BDD style, when a developer starts writing a test case, unlike writing a test method in TDD, he/she writes a “feature” belonging to a “story” which describes the feature’s expected behavior. The feature is a business-readable, domain-specific language. Then the developer runs and watches it fail; after that he/she implements the “feature” and makes the test pass just like the same process in TDD. So at its core, BDD is a specialized version of TDD that focuses on the behavioral specification of software units.

How to do it…

The typical process can be described in the following steps:

Add a feature test.
Run all tests and see if the new one fails.
Write some code.
Run the automated tests and see them succeed.
Refactorize the code.
Repeat steps 1 to 5.

Setting up an environment for Cucumber BDD on Rails

Cucumber is a tool for BDD-style development widely used in the Ruby on Rails platform. It introduced a domain-specific language (DSL) named Gherkin to allow the execution of feature documentation written in business-facing text, and implement acceptance test code in other languages (for example Ruby).

Cucumber sets up a great bridge between business people and development teams. Its natural and human readable language ultimately eliminates misunderstanding, and the regular expression “translation” layer provides the ability for developers to do anything magical and powerful!

Getting ready

Please install the following software to get started:

Ruby Version Manager
Version 1.9.3 of Ruby
Version 3.2 of Rails
The latest version of Cucumber
A handy text editor; Vim or Sublime Text

How to do it…

To install RVM, bundler, and Rails we need to complete the following steps:

Install RVM (read the latest installation guide from http://rvm.io).
$ \curl -L https://get.rvm.io | bash -s stable –ruby
Install the latest version of Ruby as follows:
$ rvm install ruby-1.9.3
Install bundler as follows:
$ gem install bundler
Install the latest version of Rails as follows:
$ gem install rails

Cucumber is a Ruby gem.
To install it we can run the following command in the terminal:

Cucumber contains two parts: features and step definitions. They are explained in the following section:
$ gem install cucumber

If you are using bundler in your project, you need to add the following lines into your Gemfile:
gem ‘cucumber’

How it works…

We will have to go through the following files to see how this recipe works:

Feature files (their extension is .feature): Each feature is captured as a “story”, which defines the scope of the feature along with its acceptance criteria. A feature contains a feature title and a description of one or more scenarios. One scenario contains describing steps.
Feature: A unique feature title within the project scope with a description. Its format is as follows:
Feature:

Scenario: This elaborates how the feature ought to behave. Its format is as follows:
Scenario:
Given

When

Then
Step definition files: A step definition is essentially a block of code associated with one or more steps by a regular expression (or, in simple cases, an exact equivalent string).
Given “I log into system through login page” do
visit login_page
fill_in “User name”, :with => “cyberman”
fill_in “Password”, :with => “cybermanPassword”
click_button “Login”
end
When running a Cucumber feature, each step in the feature file is like a method invocation targeting the related step definition. Each step definition is like a Ruby method which takes one or more arguments (the arguments are interpreted and captured by the Cucumber engine and passed to the step method; this is essentially done by regular expression). The engine reads the feature steps and tries to find the step definition one by one. If all the steps match and are executed without any exceptions thrown, then the result will be passed; otherwise, if one or more exceptions are thrown during the run, the exception can be one of the following:

Cucumber::Undefined: Step was an undefined exception
Cucumber::Pending: Step was defined but is pending implementation
Ruby runtime exception: Any kind of exception thrown during step execution
Similar with other unit-testing frameworks, Cucumber runs will either pass or fail depending on whether or not exception(s) are thrown, whereas the difference is that according to different types of exceptions, running a Cucumber could result in the following four kinds:

Passed
Pending
Undefined
Failed
The following figure demonstrates the flow chart of running a Cucumber feature:

getfile

There’s more…

Cucumber is not only for Rails, and the Cucumber feature can be written in many other languages other than English.

Cucumber in other languages/platforms
Cucumber is now available on many platforms. The following is a list of a number of popular ones:

JVM: Cucumber-JVM
.NET: SpecFlow
Python: RubyPython, Lettuce
PHP: Behat
Erlang: Cucumberl

Cucumber in your mother language
We can actually write Gherkin in languages other than English too, which is very important because domain experts might not speak English. Cucumber now supports 37 different languages.

Writing your first Hello World feature

Getting ready

In the first recipe we’ve already successfully installed Ruby, RubyGems, bundle, and Rails. To write our first Cucumber feature, we need a Rails application with Cucumber installed.

How to do it…

Now we create a Rails project and install Cucumber in the project. Follow the given steps:

Create a new Rails app, cucumber_bdd_how_to, by running the following Rails command in the terminal:

$ rails new cucumber_bdd_how_to

Add gem ‘cucumber-rails’ into the project’s Gemfile; it should be similar to the following code snippet:

source ‘https://rubygems.org’

gem ‘rails’, ‘3.2.9’

# Bundle edge Rails instead:
# gem ‘rails’, :git => ‘git://github.com/rails/rails.git’

gem ‘sqlite3’

# Gems used only for assets and not required# in production environments by default.group :assets do
gem ‘sass-rails’, ‘~> 3.2.3’
gem ‘coffee-rails’, ‘~> 3.2.1’

gem ‘uglifier’, ‘>= 1.0.3’
end

gem ‘jquery-rails’

group :test do
gem ‘cucumber-rails’
end

# To use ActiveModelhas_secure_password
# gem ‘bcrypt-ruby’, ‘~> 3.0.0’

# To use Jbuilder templates for JSON
# gem ‘jbuilder’

# Use unicorn as the app server
# gem ‘unicorn’

# Deploy with Capistrano
# gem ‘capistrano’

# To use debugger
# gem ‘debugger’

Run the bundle install in the terminal:

$ bundler install

After the installation is completed, cd into your RoR project directory and run:

$ rails generate cucumber:install

By running this, Cucumber will initialize a folder called features in your Rails project:

getfile (1)

Now we create a file under the features folder called hello_world.feature, and write down our first Cucumber test:

Feature: Learn Cucumber
As a Software Developer
I want to learn Cucumber
So that I can developer in BDD style!

Scenario: Write Hello World Cucumber
Given I have a Rails project
When I write a Hello World Cucumber test
Then I should be able to run it and see “Hello World” printed on screen

And we go to the terminal and run the following Cucumber command:

$ bundle exec cucumber features/hello_world.feature

Now we should see that it fails since we haven’t implemented the steps yet. The message should be similar to the following screenshot:

getfile (2)

Create a hello_world_steps.rb under the step_definitions directory.

Copy the code shown on the console and paste it to hello_world_steps.rb.

Modify the step code as follows:

Given /^I have a Rails project$/ do
puts “Yes, I am at my RoR project.”
end

When /^I write a Hello World Cucumber test$/ do
puts “Yeah! I just wrote my test”
end

Then /^I should be able to run it and see “(.*?)” printed on screen$/ do |arg|
puts arg
end

Now we run it again and we see it successfully passed:

getfile (3)

How it works…

In this simple example, we wrote our first Cucumber feature named “Hello World”, it has one scenario, “Write Hello World Cucumber”, with three steps. We also implemented three step definitions and successfully made it pass.

In the Cucumber feature, one step is usually started with a preposition or an adverb (Given, When, Then, And, and But), each step is parsed and corresponding to a step definition, in our previous example the last step accepts one argument to be passed in, which means you can put any word in the step, and we passed the string Hello World, so that it is printed on the screen.

References:
Instant Cucumber BDD How-to
By: Wayne Ye;
Publisher: Packt Publishing