I’m not going to tell you why you should write acceptance (or integration) tests, but you should. I used Cucumber for a while now and I love it, but I think writing my tests in a business-readable domain-specific language and translating them into Ruby using step definitions is a bit too much sometimes. And I’m not a vegetarian.
Luckily, we have Steak by @cavalle:
“Steak is like Cucumber but in plain Ruby. No explicit givens, whens or thens. No steps, no English, just Ruby: RSpec and Steak. That’s all.”
Right now the stable version of Steak only works with Rails 2.x and RSpec 1.x, but there’s a Rails 3 branch where some work is being done to support Rails 3.x and RSpec 2.×. I’ve been using that one, but this article should also be fine for you when you’re on Rails 2.×.
Installation
OK, throw this into your Gemfile
(I’m specifying the 0.4.0.a4
release here, that’s the most recent alpha release from the rails3
branch). Also, I’ll be using Capybara for this example:
group :test do
gem 'steak', '0.4.0.a4'
gem 'capybara'
end
And install your bundle:
$ bundle install
Or — if you’re using Rails 2.x — put this in config/environment.rb
(Just using the stable Rails 2 release of Steak here):
config.gem 'steak'
config.gem 'capybara'
And run:
$ rake gems:install RAILS_ENV=test
Now you can use the Steak generators to set everything up. You have to specify which driver you’re using (Steak also has a generator for Webrat):
$ rails generate steak --capybara # or -- webrat
Please remember to use script/generate
instead of rails generate
when on Rails 2.×.
The generator created the spec/acceptance
directory in your project, in which you can find acceptance_helper.rb
and the support
directory. The support
directory holds paths.rb
— which should be familiar if you’ve used Cucumber before — and helpers.rb
.
Acceptance specs
Now, let’s write our first acceptance spec — no, we’re not calling it a “feature”. It’s a spec. — by using another generator (I’m creating an articles spec here):
$ rails generate acceptance_spec articles
Steak generated spec/acceptance/articles_spec.rb
, which looks like this:
require File.dirname(__FILE__) + '/acceptance_helper'
feature "Feature name", %q{
In order to ...
As a ...
I want to ...
} do
scenario "Scenario name" do
true.should == true
end
end
If you’re a Cucumber user, the feature description should look familiar. I’ll try to describe what I’m doing like this:
feature "Articles", %q{
In order to have an awesome blog
As an author
I want to create and manage articles
} do
Great. On to our first scenario. In the articles index we want to show all articles in a list.
scenario "Article index" do
Article.create!(:title => 'One')
Article.create!(:title => 'Two')
visit article_index
page.should have_content('One')
page.should have_content('Two')
end
First, I create two articles called “One” and “Two” (please, use a tool like Machinist for that). Then I visit article_index
and check if the article titles show up. Really simple.
The last thing to do to get this thing running is to create the path for article_index
in spec/acceptance/support/paths.rb
:
module NavigationHelpers
def homepage
"/"
end
def article_index
"/articles"
end
end
Simple, right? I’m not going to walk you through building and testing this application here right now, but I think you get the point.
Minimalist acceptance testing
Steak just provides some aliases (like scenario
and feature
) for RSpec’s methods “providing you with the language of acceptance testing”. Here’s a snippet from Steak’s library:
module Spec::Example::ExampleGroupMethods
alias scenario example
alias background before
end
module Spec::DSL::Main
alias feature describe
end
So, if you know your RSpec, the only thing you’ll have to do is dive into Capybara (or Webrat) for a bit and you’ll be writing acceptance specs in no time.
Running your spec
You might have guessed, but running your acceptance specs is exactly the same as running any other spec. After all, it’s just a minimal layer on top of RSpec:
$ spec spec/acceptance/articles_spec.rb
Cucumber vs Steak?
Cucumber is highly focused on creating a business-readable DSL, and does so perfectly. I understand the thought behind making stakeholders able to read what’s going on in their projects, but I wonder how many people actually do this. Also, one might argue that — from a Ruby programmer’s perspective — Steak’s specs are in fact more readable than Cucumber’s.
Steak takes away the extra step of translating everything from English to Ruby and is incredibly easy to learn (especially when you have some RSpec experience). It’s completely incomparable to Cucumber though and which one to choose is simply a matter of taste. And I love me some Steak.