---
title: Mixing Cucumber with Test::Unit/Shoulda
teaser:
tags: web,testing,shoulda
author: Joe Ferris
published_on: 2009-02-20
---

## I don't know if cucumber is a fruit or vegetable

![''](http://images.thoughtbot.com/ui/2009-2-20-cucumber-roll.jpg)

There's a lot of buzz in the community right now about the latest framework for
top-down BDD: [Cucumber](http://cukes.info/) . Cucumber lets you describe
features in plain text, from a user's perspective. Once you have your thoughts
down in English (or [another
language](http://github.com/aslakhellesoy/cucumber/tree/master/examples/i18n)),
you can map each step of your spec to Ruby code. This perfectly complements our
love of design-driven, outside-in development.

## Let's be assertive

Most of Cucumber's users seem to be fans of RSpec, but if you're using
Test::Unit (or Shoulda), Cucumber works just as well. First, you'll have to tell
Cucumber not to use RSpec:

    # at the bottom of features/support/env.rb
    # Comment out the next two lines if you're not using
    #RSpec's matchers (should / should_not) in your steps.
    # require 'cucumber/rails/rspec'
    # require 'webrat/rspec-rails'

Next, you have to replace the matchers in the generated steps to use assertions:

    # At the bottom of features/step_definitions/webrat_steps.rb
    Then /^I should see "(.*)"$/ do |text|
      # response.body.should =~ /#{text}/m
      assert_match /#{text}/m, @response.body
    end

    Then /^I should not see "(.*)"$/ do |text|
      # response.body.should_not =~ /#{text}/m
      assert_no_match /#{text}/m, @response.body
    end

    Then /^the "(.*)" checkbox should be checked$/ do |label|
      # field_labeled(label).should be_checked
      assert field_labeled(label).checked?
    end

And that's it!

## Unauthorized cucumbers

Our freshly-released authentication framework,
[Clearance](http://wiki.github.com/thoughtbot/clearance), also has built-in
support for Cucumber. If you're using Clearance, just run `script/generate
clearance_features` and you'll get step definitions for authentication, as well
as feature files for the generated Clearance controllers for users signing up,
in, and out.

## Cucumber factories

If you're using [factory_bot](http://thoughtbot.com/projects/factory_bot) in
your project, it's much easier to implement `Given` steps that create data:

    Given /^I have created a post with a title of "(.*)"$/ do |title|
      Factory(:post, :title => title, :author_id => session[:user_id])
    end

You can get a little creative and implement wildcard steps for basic data:

    Factory.factories.each do |name, factory|
      Given /^an? #{name} exists with an? (.*) of "([^"]*)"$/ do |attr, value|
        Factory(name, attr.gsub(' ', '_') => value)
      end
    end

That will give you implementation for steps like these, assuming you have post,
author, and comment factories:

    Given a post exists with a title of "Super Post"
    Given an author exists with an email of "user@example.com"
    Given a comment exists with a title of "Bad Comment"

If you need to get anymore complicated than that, you should probably write a
custom step.

## Adding Cucumber to your diet

We wanted to add some integration tests to an existing project, and we decided
to use Cucumber. Although that does mean we won't confidently have 100% coverage
in our integration tests, they're still nice to have. But how do you add
features for existing code?

We've been writing a feature for every new client request on that project - for
each user-created ticket we handle, we create a .feature file (and include the
ticket number in the feature title), and write steps for that request. This
means that we have acceptance tests for all new client requests on that project.
This approach may seem a little strange, but it's been helpful, and we're very
happy with it so far. We'll likely take a different approach if we use Cucumber
on a project from scratch.

Now you have no excuse if your projects aren't doing any kind of top-down
testing, so get out there and write some acceptance tests!
