Rob Sullivan and Amanda Harlin have been kicking around ideas for something called Techlahoma and they recently asked me to get involved to help. We decided early on that the app would be a Rails project, and I suggested that we use Cucumber to describe the main user features that we hope to build. In the early stages these stories will act as our design document, allowing us to formally capture the description of the features that will be available to end users. These documents will live in the project repo, and will be just like any other code/text file. We'll be able to track the history of feature descriptions, make drastic changes to them without fear of losing previous work, use pull requests to initiate discussion about new features, and all of the other great benefits that you get with git and GitHub.

I had the honor of generating the new app, so here I'm going to document the steps that I took to start the project and build the first few Cucumber scenarios.

First I generated a new rails app, using postgres as the DB and using the -T option to skip Test::Unit. Then I immediately initialized the project directory as a git repo, added all of the app files to the repo, committed and pushed.

rails new techlahoma -d postgresql -T
cd techlahoma
git init .
git add .
git commit -m "Initial rails app"
git remote add origin git@github.com:techlahoma/techlahoma.git
git push -u origin master

Then I added a couple of gems to the Gemfile for running cucumber.

group :test do
  gem 'cucumber-rails', :require => false
  # database_cleaner is not required, but highly recommended
  gem 'database_cleaner'
end

Then a quick bundle install.

Then I installed the cucumber configuration and skeleton.

rails generate cucumber:install 

Now I'm ready to run cucumber!

$ cucumber 
Using the default profile...
0 scenarios
0 steps
0m0.000s

Cucumber is running, but I don't have any scenarios ready to run. Let's fix that. One of the features that we know we want to have is the ability for users to sign in and out. So, I'm going to start there with a feature description. First let's look at the feature files themselves, and then I'll describe their structure.

features/users/sign_in.feature

Feature: Sign In
  As a visiting user
  I want to sign in
  Sign in will happen via GitHub (and possibly other auth providers)

  Scenario: Sucessful sign in
    Given a signed out user
    When he visits the home page
    Then he should see "Sign In" # A link on the page
    When he signs in
    Then he should see "Sign Out"  # A link on the page

  Scenario: Failed sign in
    Given a signed out user
    When he visits the home page
    Then he should see "Sign In"
    When he fails the signs in
    Then he should see "Sign In"
    Then he should see "sorry"

features/users/sign_out.feature

Feature: Sign Out
  As a signed in user
  I want to sign out
  To protect my account stuff

  Scenario: Successful sign out
    Given a signed in user
    When he visits the home page
    Then he should see "Sign Out"
    When he signs out
    Then he should see "Sign In"

  Scenario: Failed sign out
    Given a signed in user
    When he visits the home page
    Then he should see "Sign Out"
    When he fails the sign out
    Then he should see "Sign Out"
    Then he should see "sorry"

As you can see, these feature files have two main parts. Feature and Scenario.

Feature

The Feature section is only for humans, and is meant to be a high level description of the complete feature or feature set in question. In this part you're not describing specific use cases or sequences of events, you're just describing the purpose of the feature, and the "business case" for why it exists in the first place.

Scenario

The Scenario sections are also for humans, but they're for computers too. These are descriptions of specific sequences of events that should happen within the app, and the results that should occur with those events. Generally you'll have a Scenario section for each branch, or edge case that your code will need to cover. You want to keep these descriptions still at a pretty high level, and you don't want to get into the minutia of dealing directly with UI elements. Notice that the scenarios above have only a single line for something like When he signs in. Scenario sections generally should not contain things like "she clicks on the 'sign in' link" or "she enters her email address". These kind of details will be handled later in the step definitions, which is the code that Cucumber will actually run in order to execute these Scenarios as live test code.

Now when I run cucumber I see that it's trying to execute my Scenarios but that it can't find step definitions for them. Handily it provides stubs for the missing step definitions.

4 scenarios (4 undefined)
22 steps (22 undefined)
0m0.212s

You can implement step definitions for undefined steps with these snippets:

Given(/^a signed out users$/) do
  pending # express the regexp above with the code you wish you had
end

When(/^he visits the home page$/) do
  pending # express the regexp above with the code you wish you had
end

Then(/^he should see "(.*?)"$/) do |arg1|
  pending # express the regexp above with the code you wish you had
end

When(/^he signs in$/) do
  pending # express the regexp above with the code you wish you had
end

When(/^he fails the signs in$/) do
  pending # express the regexp above with the code you wish you had
end

Given(/^a signed in user$/) do
  pending # express the regexp above with the code you wish you had
end

When(/^he signs out$/) do
  pending # express the regexp above with the code you wish you had
end

When(/^he fails the sign out$/) do
  pending # express the regexp above with the code you wish you had
end

Brainstorming

The great thing about cucumber files is that you can start will just the Feature section and allow it to act like a design document of sorts where you capture general ideas about the new feature that's being discussed. I know that one of the things we'd like to include is the ability for companies to maintain a profile that contains some basic information about the company. I'm not entirely sure what all we want to include there, so for now I'm going to start with a some basic feature files that just take a stab at describing things that might fit into this feature set.

features/company_profiles/create.feature

Feature: Company Profiles
  As a company owner/operator
  I want to create a profile for my company
  So that local developers can learn about me

features/company_profiles/tags.feature

Feature: Tags for Companies
  As a local developer
  I want to be able to filter companies based on technologies being used
  So that I can find places where my skills can be put to use

features/company_profiles/freelancers.features

Feature: Freelancer Profiles
  As a local freelancer
  I want to create a profile for myself
  So that local companies can contact me if they could use my skills

These files aren't yet executable by Cucumber, but they're a great starting point for discussion about what we want to have happen here. We can use them to flush out the ideas and zero in on the requirements. As that happens usage scenarios will begin to emerge and we'll write a Scenario section for each use case that we want to consider.

In a later installment we'll look at starting to implement some step definitions for scenarios to turn these feature files into fully executable tests.

In the mean time you can "check out the techlahoma repo":https://github.com/techlahoma/techlahoma and don't hesitate to send over some pull requests if you'd like to get involved.