Latest from the Bamboo Blog

RSpec stories are a way of doing integration and acceptance testing using plaintext executable tests. You can use them in Merb as well as Rails. Here’s how.</p>

Setting up

Install edge Merb; the latest gem (0.9.2) will not work. You need merb-core, merb-more, and merb-plugins.

Merb-plugins gives you the merb_stories gem, so you don’t need to install that separately.

Add this line to your app’s config/environments/test.rb:

dependencies "merb_stories", "webrat"

(Note that merb_stories’ README file is wrong about this, for now - and the generator will create a dependency on merb-rspec, which no longer exists. My fork fixes this.)

Now generate your story:

merb-gen story mystory

Now run your story:

rake story\\[mystory\\]

Yes, you must include the square brackets, and you have to escape them.

Writing stories

Now fill out your story. There are some differences to Rails’ versions. The best places to look for help are in the Merb code itself:

  • spec/public/test/controller matchersspec.rb
  • lib/merb-core/test/helpers
  • lib/merb-core/test/matchers

To start you off, here are the steps for a simple integration test:

steps_for(:homepage) do
  When("I visit the root") do
    @mycontroller = get("/")
  end
  Then("I should see the home page") do
    @mycontroller.should respond_successfully
    @mycontroller.body.should contain("Hello") 
  end    
end

As you write your tests, don’t trust Merb absolutely. Some things are wrong, don’t work, or aren’t meant to work [yet]. As part of debugging, look at the Merb source, and fork it and fix it if needed.

Adding Webrat

Webrat lets you write integration tests that are even closer to natural language. You can say things like:

visits '/auth/login'
fills_in 'username',:with=>"bob"
fills_in 'password',:with=>"hunter2"
clicks_button "login"
response.should be_successful
...

I’ve forked Webrat to add Merb support.

To get started, clone it, build the gem and install it.

You’ll also need to make sure you’re using the memory session store (for testing), or your sessions won’t be preserved:

Merb::Config.use do |c|
  c[:session_store] = 'memory' 
end  

Continuous integration

Autotest will run your specs continuously, but won’t run your stories. You can fix this, but stories run very slowly, since they use the full stack. At the very least, though, you want to run your stories after you deploy, in case you have “works on dev machine, dies on production” problems.

Add this to deploy.rb:

namespace :deploy do
  task :after_deploy do
    run_remote_tests
  end
  desc "Run tests on remote server"
  task :run_remote_tests do
    run "cd #{deploy_to}/current && rake spec"
    run "cd #{deploy_to}/current && rake story\[all\] MERB_ENV=test"
  end 
end

This will fail if you’re using Vendor Everything like us - it won’t be able to find merb-core. To fix it, replace stories/stories/all.rb:

env = ENV['MERB_ENV'] || 'test'
require 'rubygems'
Gem.clear_paths
Gem.path.unshift(File.join(File.dirname(__FILE__), "..","..","gems"))

require 'merb-core'
Merb.load_dependencies(:environment => env)

require 'spec'
Merb.start_environment(:testing => true, :adapter => 'runner', :environment => env)

dir = File.dirname(__FILE__)
Dir[File.expand_path("#{dir}/**/*.rb")].uniq.each do |file|
  require file
end

You’ll have the same problem with specs. Edit spec/spec_helper.rb:

Gem.clear_paths
Gem.path.unshift(File.join(File.dirname(__FILE__), "..","gems"))

Now you have natural-language integration tests that run automatically on deployment. Sweet.