One of the most debated topics in software development is testing. It often gets left to the last minute, and then cut because you’re out of time, over-budget, or whatever else. Management wonders why developers can’t just “get it right the first time”, and developers (especially on large systems) can be taken off-guard when different stakeholders describe different parts of the system, like the story of the blind men describing an elephant.
Accomplishing the evolving objectives of a software project in time and budget on a long-term basis is a difficult undertaking. Unit testing can play a vital role in meeting these demands. Unit testing is perhaps the most important technique the agile world has to offer. A well-written test suite is usually half the battle for a successful development process.
Test Driven Development is a design methodology that leverages unit testing as the primary working tool. It’s quite common to use TDD and unit testing as synonyms, but this is not correct. You cannot practice TDD without unit testing, but you can write unit tests without TDD and improve your design anyway. TDD is a test-centered development process in which we start writing tests firsts. Initially, these tests fail but as we add more application code these tests pass.
TDD (Test Driven Development) brought more confidence, facilitated implementing modifications to existing features and often lead to better code design.
Challenges with TDD
The biggest problem in classic TDD is that there is a disconnection between what the product is supposed to do and what the test suite that the development team builds is testing. TDD does not explicitly say how to connect both worlds. This leads to a lot of teams doing TDD but testing the wrong things. Yes, perhaps they were able to test all their classes, but they tested whether the classes behave as expected, not whether the product behaves as expected.
Need for BDD
BDD extends Test-driven development by writing test cases in a way anyone can understand. With the help of BDD, software development is managed by both business interests and technical insight. It focuses and associates behavioral specifications with each unit of software under development. Basically, BDD is a test-first approach where a new coding task can be created only when a change in the product happens: a new requisite, a change in an existing one, or a new bug. BDD exposes a good insight: we should test features instead of components. Some key advantages of BDD are
- Written in plain descriptive English language
- Explained as the behavior of the application and not just a particular module.
- More user focused
BDD on Rails
Ruby on Rails was the first web framework to ship with an integrated testing framework. When you generate a new Rails application with default options, it sets the scene for testing using test/unit – a testing library that comes with Ruby. However, there are tools which make BDD easier to apply. Ruby on Rails has many great frameworks which help to write automated tests such as RSpec, Capybara and Cucumber are some of the popular frameworks. We recommend using RSpec as the main testing library and Cucumber for writing high-level acceptance tests. Below is a list of gems that are needed for BDD in Rails 5.
Rspec is a unit test framework. Tests written in RSpec focus on the “behavior” of an application being tested. RSpec does not put emphasis on, how the application works but instead on how it behaves.
1. group :development, :test do gem 'rspec-rails', '~> 3.7' end 2. bundle install 3. rails generate rspec:install The above command adds a new ‘spec’ directory to the rails project folder. 4. bundle exec rspec The above command executes your rspec tests
require "rails_helper" RSpec.describe Article, :type => :model do context "with 2 or more articles" do it "sorts them in reverse order" do article= Article.create! commentOne = article.comments.create!(:body => "comment one") commentTwo = article.comments.create!(:body => "comment two") expect(article.reload.comments).to eq([commentTwo, commentOne]) end end end
Cucumber reads plain-text descriptions of application features with example scenarios and uses the scenario steps to automate interaction with the code being developed. Because they can be read by anyone, you can use them to help improve communication, collaboration and trust.
Installing Cucumber 1. group :test do gem 'cucumber-rails', require: false end 2. bundle install 3. rails generate cucumber:install 4. bundle exec cucumber
Cucumber tests are divided into individual Features. These Features are subdivided into Scenarios, which are sequences of Steps.
Feature: Hello Cucumber Scenario: User clicks the link Given I am on the homepage When I click the provided link Then I should see the link click confirmation For each scenario, we need to provide the corresponding steps definitions as a ruby code. The below is an example step definition Then(/^I should see the link click confirmation$/) do expect(page).to have_content("confirm") end
Although we say BDD is a better approach, we must not forget that BDD has actually evolved from TDD, as a way to eliminate the shortfalls of TDD. So there is absolutely no harm in implementing both approaches – one to support the quality of the code the developer writes, and the other to support the behavior of the system defined by the product owner.