Rails Cucumber / Machinist Tutorial: Machinist with Cucumber in 10 minutes
Update
A newer version of this rails and cucumber tutorial, using rails 3 and ruby 1.9 is available here.
I’ve had a lot of traffic for machinist, but my earlier post isn’t very useful for actually using it.
So, here’s how to start using machinist with cucumber in a rails app. I’ll use a simple app that deals with strawberries.
Start a rails app
1 2 3 4 5 6 7 |
sudo gem install rails --source=http://gems.rubyonrails.org rails strawberries cd strawberries script/generate nifty_layout # this is from the nifty_scaffold gem, which I recommend. |
Grab the gems
1 2 3 4 5 |
sudo gem install cucumber --no-ri --no-rdoc sudo gem install notahat-machinist --no-ri --no-rdoc # if this doesn't work, try doing: # gem sources -a http://gems.github.com |
Then add them to your test environment, so that other folks on your team can easily get them.
1 2 3 4 5 6 |
# config/environments/test.rb config.gem 'cucumber' config.gem 'notahat-machinist', :lib => 'machinist' config.gem 'faker' |
Generate the files
From your rails app’s root, enter:1 2 |
script/generate cucumber touch features/support/blueprints.rb |
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 |
# features/strawberries.feature In order to live people want to be able to eat strawberries 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 features |
Now we can add the step definition for the strawberries.
1 2 3 4 5 |
#features/step_definitions/strawberry_steps.rb Given /^a strawberry that is "(.*)"$/ do |color| Strawberry.make(:color => color) end |
Now let’s try rake:features again. This time we get
1 |
uninitialized constant Strawberry (NameError) |
Which means it’s time to start adding code.
Implement feature and add blueprints
Now that we’ve written some tests, we can go ahead and build this.
1 2 3 |
script/generate 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 |
rake features |
This time we get No blueprint for class Strawberry (RuntimeError).
So, let’s add a blueprint:
1 2 3 4 5 6 7 8 |
#features/support/blueprints.rb Sham.color { Faker::Lorem.words(1).first.downcase } Strawberry.blueprint do color {Sham.color} 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 #
So, to fix this, let’s add a root path.
1 2 3 4 |
# config/routes.rb map.root :controller => 'strawberries' |
And then try rake features again. This time we get:
1 2 3 4 5 6 |
Then I should see "There is 1 strawberry" # features/step_definitions/webrat_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 5 |
# 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:features again, I see that now only the last step is failing. Then I should see “Strawberry eaten!” # features/step_definitions/webrat_steps.rb:89 expected: /Strawberry eaten!/m,
So, let’s fix that too.
1 2 3 4 5 6 7 8 9 10 |
# 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 |
momoro:~/Projects/Rails/strawberries$ rake features (in /Users/mischa/Projects/Rails/strawberries) 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 |
User.blueprint do password {'password'} password_confirmation ['password'} name {Sham.name} end |
here, it would be annoying to have to specify the passowords each time, so it’s easier to let machinist do it, so that you can just say User.make, or User.make(:name => ‘mischa’).
Cucumber note
As you write more features, it will become annoying to run all of them constantly. To run only one feature at once use rake features FEATURE=features/feature_name.feature
Alternatively, use autotest with cucumber by adding “export AUTOFEATURE=true” to your bash profile.
March 08, 2009


Sweetness! Thanks for the tips on machinist in cucumber.
On an aside, I made a rake task to simplify the rake command to run 1 or more features as I had to type '--require features --require lib' every time I ran a single feature or it wouldn't work.
Thanks for the help, the example worked great!
March 18, 2009 at 8:54 PMWhen I'm getting a Webrat::NotFoundError, I would like to see the actual HTML Webrat got. How do I do that?
March 25, 2009 at 12:55 AMI'm reproducing here the response you sent me by e-mail. Maybe others will find it useful.
March 25, 2009 at 2:25 AMYou invited me to upgrade my webrat version (I'm already at 0.4.3) or to use your plugin:
http://github.com/mischa/cucumber_rails_debug/tree/master
To use it, just put "Then what" inside of any feature, and it will show you the html that webrat sees at that moment.
Check out Dr. Nic's tmbundle for Machinist. It examines your AR models and creates skeletal blueprints in spec/blueprint.rb.
April 16, 2009 at 4:22 PM@steve, great tip! I actually don't use textmate unfortunately (i'm a die hard vim guy), but definitely something to look at for those who do.
April 16, 2009 at 10:24 PM