back

Rails 3 Cucumber / Machinist Tutorial: Machinist with Cucumber in 10 minutes

Erwin was kind enough to update my cucumber and machinist tutorial for Rails 3. This should be really useful for people who want to use cucumber to test with Rails 3. He notes that this is current with Rails3.rc and ruby 1.9.2.rc.1.

You can find his full repo here.

Rails 3 cucumber tutorial

So, here’s how to start using machinist with cucumber in a rails 3 app. I’ll use a simple app that deals with strawberries.

Start a rails app

1
2
3
4
5
6
7
8
9
10
11
12
13

# sudo gem install rails --pre --source=http://gems.rubyonrails.org
# or use rvm to test Rails 3

rails new strawberries
cd strawberries
#  install http://github.com/ryanb/nifty-generators
#To use Nifty Generators with Rails 3 you will need to include it in your Gemfile.
  gem "nifty-generators"

rails g nifty:layout
# other generators :  nifty:scaffold, nifty:config, nifty:authentification

Add them to your Gemfile, so that other folks on your team can easily get them.

1
2
3
4
5
6
7
8
9
10
11

gem 'database_cleaner'
gem 'cucumber-rails'
gem 'cucumber'
gem 'rspec-rails'
gem 'spork'
gem 'launchy   # so we can use : Then show me the page

gem 'machinist', '>= 2.0.0.beta1'
gem 'faker'

1
2
3
4
5
6
7
8

#Then install the gems by running:
 bundle install

# generate schema
rake db:migrate
# or alter /config/boot.rb if you do not intend to use a database

Generate the files

From your rails app’s root, enter:

1
2
3
4
5
6
7
8
9


rails g cucumber:install --capybara
rails g machinist:install

touch features/support/blueprints.rb
# add this line in it
require 'machinist/active_record'

Write a story

Now that we have our environment setup, let’s add the stories. These are just sketches of how our app should behave.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

@wip : cucumber tag for work-in-progress


# features/strawberries.feature
Feature: Live
  In order to live
  people
  want to be able to eat strawberries
 
@wip 
  Scenario: Eating strawberries
    Given a strawberry that is "blue"
    When I go to the homepage
    Then I should see "There is 1 strawberry"
    When I follow "eat the blue strawberry"
    Then I should see "Strawberry eaten!"

Implement steps

It’s a good idea to implement steps first, so that you can have failing steps to work with. Cucumber will provide step definitions for us, so just enter:

1
2
3

rake cucumber:wip

Now we can add the step definition for the strawberries.

1
2
3
4
5
6
7
8


#features/step_definitions/strawberry_steps.rb
Given /^a strawberry that is "(.*)"$/ do |color|
  Strawberry.make!(:color => color)
end
  

Now let’s try rake cucumber:wip This time we get

1
2
3
4

1
uninitialized constant Strawberry (NameError)

Which means it’s time to start adding code.

Implement feature and add blueprints</h3

Now that we’ve written some tests, we can go ahead and build this.

1
2
3
4

rails g nifty:scaffold strawberry color:string
rake db:migrate

Again, I’m using the nifty generator, which saves lots of time for making quick demo apps. Also, we’re going to want to add a strawberry blueprint, so that we can use Machinist. So, again, let’s try

1
2
3
4

rake cucumber:wip
# => No master blueprint defined for class Strawberry

This time we get No blueprint for class Strawberry (RuntimeError). So, let’s add a blueprint:

1
2
3
4
5
6
7

#features/support/blueprints.rb

Strawberry.blueprint do
  color {Faker::Lorem.words(1).first.downcase}
end

This gives us the ability to say Strawberry.make, which will create a new strawberry with a random color. The nice part about machinist is that we can do both Strawberry.make and Strawberry.make(:color => ’red’), which becomes really useful when you have a model with a lot of validations that you don’t want to have to specify every time. Machinist lets you focus on specifying only what’s important to the specific test. Now, at this point, since I used the nifty_scaffold gem, we just have to change some text to make the feature pass, and we’re done.

So, now that we have a blueprint, let’s try rake:features again. We get undefined method `root_path’ for # (NoMethodError).

So, to fix this, let’s add a root path and delete public/index.html.

1
2
3
4
5

# config/routes.rb

root :to => "strawberries#index"

And then try rake features again. This time we get:

1
2
3
4
5

Then I should see "There is 1 strawberry"  # features/step_definitions/web_steps.rb:89
      expected: /There is 1 strawberry/m,
           got: "<! #etc etc

So, what’s happening here is that cucumber/webrat are going to our home page, but they aren’t finding the text that we wrote that we wanted to see in the story. So, let’s change it.

1
2
3
4

# app/views/strawberries/index.html
<h1>There is <%= "#{Strawberry.count}" -%> strawberry</h1>

Now if we try rake features again we get Could not find link with text or title or id “eat the blue strawberry” (Webrat::NotFoundError) So we add that link

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

<h1>There is <%= "#{Strawberry.count}" -%> strawberry</h1>
<table>
  <tr>
    <th>Color</th>
  </tr>
  <% @strawberries.each do |strawberry| %>
    <tr>
      <td><%=h strawberry.color %></td>
      <td><%= link_to "Show", strawberry %></td>
      <td><%= link_to "Edit", edit_strawberry_path(strawberry) %></td>
      <td><%= link_to " eat the #{strawberry.color} strawberry", strawberry, 
:confirm => 'Are you sure?', :method => :delete %></td>
    </tr>
  <% end %>
</table>

If I try rake cucumber:wip again, I see that now only the last step is failing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Then I should see “Strawberry eaten!” # features/step_definitions/web_steps.rb
expected: /Strawberry eaten!/m,

000

So, let’s fix that too.

---RUBY

# app/controllers/strawberries_controller.rb

  def destroy
    @strawberry = Strawberry.find(params[:id])
    @strawberry.destroy
    flash[:notice] = "Strawberry eaten!" #change the flash
    redirect_to strawberries_url
  end

So, now we have 5 passing steps

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

…./strawberries$ rake cucumber:wip

Feature: Live
In order to live  # features/strawberries.feature
  people
  want to be able to eat strawberries
  Scenario: Eating strawberries                # features/strawberries.feature:5
    Given a strawberry that is "blue"          # features/step_definitions/strawberry_steps.rb:2
    When I go to the homepage                  # features/step_definitions/webrat_steps.rb:6
    Then I should see "There is 1 strawberry"  # features/step_definitions/webrat_steps.rb:89
    When I follow "eat the blue strawberry"    # features/step_definitions/webrat_steps.rb:14
    Then I should see "Strawberry eaten!"      # features/step_definitions/webrat_steps.rb:89


1 scenario
5 steps passed

Machinist note So, hopefully this is enough for you to get started with. The value of machinist really comes later, when you have a model with more than 1 field, and when you need to make a bunch without wanting to specify everything every time. For example:

1
2
3
4
5
6
7

User.blueprint do
  password {'password'}
  password_confirmation {'password'}
  name {Faker::Lorem.words(1).first}
end

Here, it would be annoying to have to specify the passwords each time, so it’s easier to let machinist do it, so that you can just say User.make!, or User.make!(:name => ’mischa’).

August 04, 2010