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 Scenario
s as live test code.
Now when I run cucumber I see that it's trying to execute my Scenario
s 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
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.