Fasten your TDD red-green-refactor cycles

Having recently been bit by the TDD bug, I’ve been researching a lot about best practices when it comes to testing and speeding up the red-green-refactor process and I recently came across a really neat way to fasten the cycles further.

Guard - is a command line tool that allows you to handle events on file modifications. What that means is you can essentially configure it to monitor for modifications to specific files on your file system and perform corresponding actions. It is a great utility and can be used for carrying out a wide variety of actions.

There is a big list of ‘Guards’ available, which are essentially extensions for guard to guard specific types of files, you can find the list here in the Guard Wiki

Installation :

I would recommend you to use bundler to maintain your gem dependies, if you are doing so, simply add the following in your Gemfile

gem 'guard'
gem 'guard-rspec'
gem 'guard-cucumber'

gem 'rb-inotify'
gem 'libnotify' # This is optional for notifications on linux, for other OS' please look at https://github.com/guard/guard#readme for details for other OS'

Or if you’re not using bundler, simply install the above mentioned gems
manually. After having done that you can perform the following steps to setup
guard and configure it for both rspec & cucumber

    $ guard init          # This creates an empty Guardfile in the project's root, which it uses for configurations.
    $ guard init rspec    # This adds rspec guard to the Guardfile
    $ guard init cucumber # This adds cucumber guard to the Guardfile

If you now look at your Guardfile, you will see something like this :

    # A sample Guardfile
    # More info at https://github.com/guard/guard#readme

    guard 'cucumber' do
      watch(%r{^features/.+\.feature$})
      watch(%r{^features/support/.+$}) { 'features' }
      watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
    end

    guard 'rspec', :version => 2 do
      watch(%r{^spec/.+_spec\.rb$})
      watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
      watch('spec/spec_helper.rb') { "spec" }

      # Rails example
      watch(%r{^spec/.+_spec\.rb$})
      watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
      watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
      watch(%r{^app/controllers/(.+)_(controller)\.rb$})  { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
      watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
      watch('spec/spec_helper.rb') { "spec" }
      watch('config/routes.rb') { "spec/routing" }
      watch('app/controllers/application_controller.rb') { "spec/controllers" } # Capybara request specs
      watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
    end

The Guardfile is quite self-explanatory, but you can have a look at
https://github.com/guard/guard#readme for more details.

After having done that, all you need to do is start guard by issuing :

guard [start] # start is optional

Now whenever you create or modify either your spec or cucumber feature files, guard will automatically run the tests for your for the individual file that has been modified / added. This is really cool since all you need to do is write your tests and save the files and it will automatically run your tests.

If you have installed the library for notifications (libnotify in linux), you will see a cool notification of the tests instantly, indicating with the help of an icon whether the tests passed or failed. This is indeed a faster approach to following the red-green-refactor TDD cycles.


More with cucumber.

Sometime back we wrote about getting started with cucumber. Hope you liked it. In this post I want to share you some tips which will make your cases more elegant and managable.

DRYing your test cases.

When you start using cucumber exhaustively,  you will notice at one point that you end up writing the same steps again and again. And gradually  when your feature file grows bigger and bigger it becomes very tough manage.

  Feature: Signin
    As a registered user
    I want to signin with my details
    So that I can access my dashboard

  Scenario: Successful sign in
    Given I am a registered user and my email is "deepak@example.com" and my password is "password"
    When I am on the "signin" page
    And I fill in "Email" with "deepak@example.com"
    And I fill in "Password" with "password"
    And I press "Sign In"
    Then I should be on the "dashboard" page
    And I should see "Signed in successfully."

  Scenario: Checking unread messages
    Given I am a registered user and my email is "deepak@example.com" and my password is "password"
    When I am on the "signin" page
    And I fill in "Email" with "deepak@example.com"
    And I fill in "Password" with "password"
    And I press "Sign In"
    Then I should be on the "dashboard" page
    And I should see "Signed in successfully."
    When I have "2" unread messages
    Then I should see "you have 2 unread messages."

  Scenario: Checking the recent activites
    Given I am a registered user and my email is "deepak@example.com" and my password is "password"
    When I am on the "signin" page
    And I fill in "Email" with "deepak@example.com"
    And I fill in "Password" with "password"
    And I press "Sign In"
    Then I should be on the "dashboard" page
    And I should see "Signed in successfully."
    When I have some recent activities
    Then I should see those recent activities in the dashboard

If you look at the above example, in every scenario, 7 steps are repeated again and again. The ideal solution is to DRY them up. Cucumber allows you accomplish this by setting up a background.

  Feature: Signin
    As a registered user
    I want to signin with my details
    So that I can access my dashboard

  Background:
    Given I am a registered user and my email is "deepak@example.com" and my password is "password"
    When I am on the "signin" page
    And I fill in "Email" with "deepak@example.com"
    And I fill in "Password" with "password"
    And I press "Sign In"
    Then I should be on the "dashboard" page
    And I should see "Signed in successfully."

  Scenario: Checking unread messages
    When I have "2" unread messages
    Then I should see "you have 2 unread messages."

  Scenario: Checking the recent activites
    When I have some recent activities
    Then I should see those recent activities in the dashboard

This way of writing the repetitive steps in the background is best a practice to follow. It is worth knowing that the background is executed before the every scenario is executed. Which means the order of execution will be,

Background -> Scenario1,
Background -> Scenario2,
Background -> Scenario3.

Sadly you can only set up a single background for every feature. It would be really interesting if cucumber had allowed backgrounds with a context. Which means we could have some thing like,

Background1 -> Scenario1
Background1 -> Scenario3
Background1 -> Scenario5

Background2 -> Scenario2
Background3 -> Scenario4

The only way we can accomplish the above is to break them into multiple features.

#feature1
Background1 -> Scenario1
Background1 -> Scenario3
Background1 -> Scenario5

#feature2
Background2 -> Scenario2
Background3 -> Scenario4

DRYing up further more
If you are lazy enough to break it down into multiple features, then there is some good news for you. Yes, cucumber allows you to group a set of steps into a single step, and this can be done in your step definition.

  Scenario: Successful sign in
    Given 'I "deepak@example.com" have an invitation for the role "Admin"'
    Then 'I should receive an email'
    When 'I open the email'
    Then 'I should see "Invite to join example.com" in the email subject'
    And 'I should see "Click here to sign up" in the email text body part'

You can group all of the above steps into one.

  #In your step definition
  Given /^I have opened my invitation email and clicked the sign up link$/ do |arg1|
    Given 'I "deepak@example.com" have an invitation for the role "Admin"'
    Then 'I should receive an email'
    When 'I open the email'
    Then 'I should see "Invite to join example.com" in the email subject'
    And 'I should see "Click here to sign up" in the email text body part'
  end

Once you have done the above, you can use it directly in your feature.

  Scenario: Successful sign in
    Given I have opened my invitation email and clicked the sign up link


Follow

Get every new post delivered to your Inbox.