Getting started with Cucumber and Sinatra

UPDATE Sinatra and cucumber integration has changed now, Rob Holland updated the wiki to reflect it. There is also a more full featured example on his branch of cucumber. I’ve updated the blog to reflect that.

Sinatra is probably the most popular ruby micro web framework at the moment. Its simple dsl for quickly creating web apps, it give you “just enough” framework to get things done.

Cucumber is that latest development from the BDD / RSpec guys. Cucumber lets you describe the behaviour of your software in plain text. These files then serve as automated tests and documentation.

I’ve been considering using both of these tools for an upcoming project so I wanted to make sure they worked happily together. A quick google seemed to suggest that some work had been done, but I could find a tutorial for getting up and running. Happily the latest releases of Cucumber (and Webrat) have Sinatra support built in so its really very easy!

With cucumber you write your plain text specifications in terms of ‘features’, by convention they are in a features directory with the .feature extension. So for our purposes we will start with a very simple feature:

Feature: view pages

  Scenario: Home page
    Given I am viewing "/"
    Then I should see "Hello, world!

To run our feature (and test our code against it) is as simple as cucumber feature/home.feature.

cucumber pending steps

Cucumber parses the feature and looks for matching step definitions. As we can see in the screenshot we need to implement the steps in our feature so cucumber knows how to run it. Step definitions are implemented in ruby.

Given /^I am viewing "(.+)"$/ do |url|
  visit(url)
end

Then /^I should see "(.+)"$/ do |text|
  response_body.should =~ Regexp.new(Regexp.escape(text))
end

These two simple steps make use of webrat to request the url from our app and check that the response contains the text we’re looking for.

cucumber failing without webrat

The feature is currently failing as a method we have used in our step definition doesn’t exist. visit is a method from webrat so we need to configure cucumber’s environment to use webrat. Webrat has a SinatraSession specifically for testing sinatra web apps. We will also need to require the RSpec expectations as we are using them to check the response.

require 'spec/expectations'
require 'webrat'
Webrat.configure do |config|
  config.mode = :sinatra
end

World do
  Webrat::SinatraSession.new
end

Running the scenario again, and we see that everything is hooked up properly and the scenario is failing (as expected because we haven’t written any code).

cucumber failing no code

Now we have our failing scenario we can start putting together our web app and make sure we’re running with a green light!

require 'sinatra'

get '/' do
  "Hello, world!"
end

Now if we run out scenario again unfortunately it still fails, we need to hook cucumber up to our app.

require 'spec/expectations'
require 'webrat'
Webrat.configure do |config|
  config.mode = :sinatra
end

World do
  Webrat::SinatraSession.new
end

require File.dirname(__FILE__) + '/../../hello''

Finally running cucumber gives us that nice green feeling.

green cucumber

The only thing left to do is to add a rake file to run our features for us.

require 'rubygems'
require 'cucumber/rake/task'

Cucumber::Rake::Task.new(:features) do |t|
  t.cucumber_opts = "--format pretty"
end

rake features

All of the code for this getting started guide is available from gist.