RSS

CEK.io

Chris EK, on life as a continually learning software engineer.

Cucumber: The Basics

Cucumber is useful, right? It provides “behavior driven development with elegance and joy”.

But some call Cucumber “no more than a clumsy wrapper over basic integration tests”, insisting that “Cucumber’s syntax is costly” and recommending that programmers “swap Cucumber for pure integration tests using Capybara”. Others agree, but argue that the benefit of Cucumber is for the product manager, not the programmer.

Ryan Bates, for one, likes Cucumber (or did as of 2009, when he published this RailsCast…):

It might seem like quite a lot of work to define the tests in English and implement each step one at a time, but Cucumber testing has several advantages. With it you’re testing your whole stack, so you’re writing tests that cover everything from the user interface down to the database. While they’re not a replacement for unit tests, they provide an excellent way of writing high-level tests to test the overall behaviour of your application.

I side with the nuanced view: Cucumber tests seem like a lot of extra work for an integration test that can be implemented using Capybara. That said, there’s enough of a pro-Cucumber audience espousing the advantages—BDD, outside-in development1, user stories, readability—that it’s worth being familiar.

How does it work?

Cucumber2 boils down to:

  1. Cucumber definition(s) (a .feature file): this file defines both:
    • the feature itself (syntax of “In order”, “As a” and “I Want”)
    • one or more scenarios (“Given”, “When”, and “Then”).
    Note: the Cucumber definition is enough to run cucumber from the command line, though it will return a message describing skipped and undefined steps.
  2. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    Feature: Manage Articles
        In order to make a blog
        As an author
        I want to create and manage articles
        
        Scenario: Articles List
          Given I have articles titled Caching, Cucumber, Redis
          When I go to the list of articles
          Then I should see "Caching"
          And I should see "Cucumber"
          And I should see "Redis"
  3. Step definition(s): these connect to the aforementioned cucumber steps, using Ruby code inside the blocks following each of the “Given”, “When”, and “Then” regexes.
  4. (view_articles_steps.rb) download
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    Given /^I have articles titled (.+)$/ do |titles|
      titles.split(', ').each do |title|
        Article.create!(:title => title)
      end
    end
    
    When /^I go to the list of articles$/ do
      click_on "All articles"
    end
    
    Then(/^I should see "Caching"$/) do
      expect(page).to have_content "Caching"
    end
    
    Then(/^I should see "Cucumber"$/) do
      expect(page).to have_content "Cucumber"
    end
    
    Then(/^I should see "Redis"$/) do
      expect(page).to have_content "Redis"
    end
    

It’s really that simple. And it does require extra effort—even the copying of the Cucumber definition into the step definition regex feels wrong—but the process is easy enough.

What it comes down to is a different syntax for a behavior-driven process or integration test. Cucumber is one more way to implement it (in addition to Capybara, etc.). Where Cucumber really has its value is in its different syntax, which is more human-readable, meaning a non-technical person can write the Cucumber definitions (which are then implemented as step definitions).

So there may be limited value for a promgrammer on his or her own, but Cucumber can be valuable for a company or team as a whole.


  1. Avdi Grimm walks through outside-in testing nicely (albeit with more programming complexity/sophistication than Cucumber) in this video, in which he references the Cucumber “given/when/then” syntax.

  2. For a full outline of configuring a Cucumber environment, Daniel Chang outlines the setup here.