Skip to content

Instantly share code, notes, and snippets.

@jraines
Created May 1, 2011 21:07
Show Gist options
  • Save jraines/950876 to your computer and use it in GitHub Desktop.
Save jraines/950876 to your computer and use it in GitHub Desktop.
Cucumber intro

##Scope and intro

I will be focusing on Rails 3 since this will be most applicable for greenfield development, and because there are Rails 2 bugs. To get started add the following to the Gemfile:

group :test do
  gem 'cucumber'
  gem 'cucumber-rails'
  gem 'capybara'
  gem 'database_cleaner'
end

Then run:

bundle install
rails g cucumber:install --capybara

Potentially quirky things I needed to do to get it working:

rake db:test:prepare

In config/environments/test.rb (probably should be in an initializer if it's going to be a long term bug):

require 'test/unit/testresult'
Test::Unit.run = true

This is a workaround for [https://github.com/aslakhellesoy/cucumber-rails/issues/97](This issue with cucumber-rails)

Lastly, make sure that the gem's bin folder with the cucumber executable is in your PATH.

##What is it?

Cucumber supports collaboration and communication between stakeholders and the delivery team. It uses a simple language for describing scenarios that can be written and read with ease by both technical and non-technical people. These scenarios represent customer acceptance tests.

##Why should we use it?

  • "Although you can automate almost anything with it, the killer feature of Cucumber is the ease of web workflow testing."
  • "So why should you write in a natural language? . . . Think about how you would explain using the website to the stakeholder of the feature. It doesn’t matter that the stakeholder doesn’t care about your nifty cucumber features. How would (s)he explain it to you? ... [T]he natural language is closer to your understanding of the problem you’re trying to solve. When I write in code, my programmer side becomes active. My programmer side is focused on solutions. But I want to delay the solution as long as I can, until we have a decent understanding of the problem." -Iain Hecker

##But we have RSpec . . .

In our Rails work, Cucumber stories do not substitute for rspec unit tests. The two go hand in hand. In practice, the unit tests tend to drive development of the models and controllers, and the [Cucumber] stories tend to drive development of the views (we tend not to write rspec for our views) and provide a good test of the application as a whole from the user's perspective.

~Abie Hadjitarkhani on [http://stackoverflow.com/questions/393622/rspec-vs-cucumber-rspec-stories](Stack Overflow question RSpec vs. Cucumber stories)

##How do we use it?

We write Cucumber features, which are composed of scenarios, which are composed of steps. We do our actual test implementation by defining those steps as step definitions.

###Features

A feature is a high level requirement expressed from the perspective of a user. It should express what needs to be done, who needs to do it, and why they need to do it. These follow the template: In order to . . ., As a . . ., I want to . . .. This template is not programmatically enforced; it comes from recommendations about user story writing from XP methodology.

In the file features/submit_link.feature we will write the following:

Feature: Content wrangler adds a post
  In order to expand the directory
  As a content wrangler
  I want to add a post

When we run the 'cucumber' command, it will run all .feature files in the features directory, which was created when you ran the generator.

###Scenarios

Scenarios delineate what the user could encounter while trying to achieve their goal. These could be success, or any number of conditions which prevent success which we want to consider and provide for in the system.

Scenario:  Post's link url already exists in system

###Steps

These describe the conditions of the scenario, the actions that occur, and the outcomes of those actions. They are a single line of text that starts with one of these keywords: Given (condition of the scenario), When (event in the scenario), Then (expected outcome). These can each be expanded on by additional lines starting with And or But

Scenario: Link already exists
    Given a post with url "www.google.com" already exists
    When I go to the submit post page
    And I fill in "Url" with "www.google.com"
    And I press "Create Post"
    Then I should see "Error"

We're cheating just a bit here. The middle three steps use the provided helper file features/support/web_steps.rb. It has predefined steps for interacting with a page, such as "fill in", and "press". These use the Capybara/Webrat, which we'll cover later. It is recommended that for your lasting tests, you do not use these, but write your own.

We have now specified the first of the steps, but we have to implement it so that when we run the cucumber command, the steps actually test what we want them to. To accomplish this, we'll run the cucumber command and look at the output.

###Step definitions

The output should tell you that you have 1 scenario and 1 step, both undefined, and give you a snippet of code to get you started writing the step definition:

Given /^a post with url "([^"]*)" already exists$/ do |arg1|
  pending # express the regexp above with the code you wish you had
end

We will copy that snippet into a new file: features/step_definitions/link_submission_steps.rb and edit it to reflect the application state it describes, like this:

Given /^a post with url "([^"]*)" already exists$/ do |url|
  Post.create(:url => url)
end

Now you will notice the next failing step gives you a hint of what to do next:

features/step_definitions/web_steps.rb:48 Can't find mapping from "the submit post page" to a path. Now, go and add a mapping in /Users/jeremy/Sites/Rails/jeremy/blog/features/support/paths.rb

You get this message because of the navigation helper methods provided by Cucumber in that paths.rb file. You can match plain English like "the submit post page" to a Rails route. Add a matcher to that file:

when /the submit post page/
      new_post_path

Now let's run cucumber again.

Provided we have a url uniqueness validation in our model and we render the text "Error" on the page the user sees after submitting a duplicate url, all the steps should now pass.

Word of Caution . . .

####"Cucumber [is of] greatly diminished value outside of BDD." -Lee Edwards, Pivotal Labs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment