BDD Code
Behavior Driven Development a.k.a BDD is a recent and modern software development agile framework. While writing software using BDD, we use different tools but code is structured in similar way. It consist of following
-
Feature Files
Feature files are the set of features/stories and scenarios in it. Feature files are generally written in the business readable Domain Specific Language [DSL] called “Gherkin“. Gherkin use ‘Given When Then’ a.k.a GWT format for the scenarios. The feature file has .feature extension. Gherkin can be understood by most of the BDD tools. The feature file may look like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Feature: Sports In order to know about different sports As a sport fan I want list of some sports Scenario: List of the sports Given the system knows about the following sports:: | name | player | | Cricket | Sachin Tendulkar | | Tennis | Andy Murray | | FootBall | David Beckham | When the client requests GET /sports Then response should be "200" And the JSON response should be an array with 3 "name" elements And response should be JSON: """ [ {"name": "Cricket", "player": "Sachin Tendulkar"}, {"name": "Tennis", "player": "Andy Murray"}, {"name": "FootBall", "player": "David Beckham"} ] """ |
-
Step Definitions
The step definitions is the code which glue the gap between business logic and technical aspect. This code makes Gherkin feature work. The step definitions can be written in the different language. The example for the step definition file with Cucumber and Ruby for the above feature file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
When /^the client requests GET (.*)$/ do |path| get(path) end Then /^response should be JSON:$/ do |json| JSON.parse(last_response.body).should == JSON.parse(json) end Then /^response should be "([^"]*)"$/ do |status| last_response.status.should == status.to_i end Then /^the JSON response should be an array with (\d+) "([^"]*)" elements$/ do |num, name| page = JSON.parse(last_response.body) page.map { |d| d[name] }.length.should == num.to_i end |
-
Support Code
The support code consist of configuration of the environment and driver (selenium, phantomjs etc ) for the web acceptance framework. The example of the support code file for the cucumber (env.rb)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
require File.join(File.dirname('__FILE__'), 'sports_app') require 'rack/test' require "Capybara" require "Capybara/cucumber" require "rspec" require 'capybara/poltergeist' Capybara.default_driver = :poltergeist Capybara.register_driver :poltergeist do |app| options = { :js_errors => false, :timeout => 120, :debug => false, :phantomjs_options => ['--load-images=no', '--disk-cache=false'], :inspector => true, } Capybara::Poltergeist::Driver.new(app, options) end module AppHelper def app SportsApp end end World(Rack::Test::Methods, AppHelper) |
-
Hooks
Hook is the piece of code that can be run before or after each scenario, feature, suite or step. There are different types of hook. [hook.rb]
1 2 3 4 5 6 7 |
Before do SportsApp.data = [] end After do puts "Go To Bed" end |
-
Config
The config file can be used to set profile with which we can run our features. This file can also used to generate reports. [cucumber.yml
1 2 3 |
default: --profile html_report --profile rack html_report: --format progress --format html --out=report/features_report.html rack: --tags @rack |
-
Dependencies
There are different dependency management system for different programming languages. e.g Composer for PHP, bundler for Ruby.
We have example ‘Gemfile’ where we declare all our dependencies.
1 2 3 4 5 6 7 8 9 10 11 12 |
source 'http://rubygems.org' gem 'sinatra', '1.3.1' gem 'json', '1.6.3' gem 'cuke_sniffer' gem "poltergeist" group :test do gem 'cucumber', '1.1.3' gem 'rspec', '2.7.0' gem 'rack-test', '0.6.1' end |
Report
This may be optional but you can create a directory for storing html reports and other reports like cuke_sniffer reports. On CI boxes, you can create and delete these directories temporarily.
BDD code structure for me looks like this in my Sublime Text
BDD Code Analysis with Cuke Sniffer
Cuke_sniffer is the ruby gem and can be used for the code analysis for any cucumber project.
Installation
In order to use Cuke_Sniffer’ you need to have ruby version above 1.9.3.
1 |
$ gem install cuke_sniffer |
Or Simply add this to your projects ‘Gemfile’
1 |
gem 'cuke_sniffer' |
Now update the bundle
1 |
$ bundle install |
You are done and ready to use cuke_sniffer.
Usage
Now navigate to your project where features directory is located and run
1 |
$ cuke_sniffer |
When I run it with demo project, I got
We can generate Cuke_sniffer html reports like this
1 |
$ cuke_sniffer --out html report/cuke_sniffer.html |
This will generate html report and for the code analysis.
Benefits of Cuke_sniffer
- Cuke_sniffer analyses all feature file, step definitions and hooks for improvements
- Cuke_sniffer tells us about any dead steps
- Cuke_sniffer detect smells in the feature files and step definitions
- Cuke_sniffer detect how many times hooks are used
GitHub
Source code of this demo is available on the GitHub
HTML Report can be found here.
Conclusion
Cuke_sniffer can be used in the any Cucumber project for better BDD code and improve code continuously.