Cucumber, Capybara, and the joys of integration testing in Rails
Posted: - Modified: | geek, railsDevelopment is so much more fun with test cases. They give you a big target to aim for, and it feels fantastic when you write the code to make them pass. Tests also avoid or shorten those late-night “oh no! I broke something!” sessions, because you can backtrack to versions that pass the tests. (You are using version control, right?)
So naturally, as I worked on my first IBM project using Ruby on Rails, I wanted to know about how to perform automated testing – not just at the unit level, but at the web/integration level.
I like using Simpletest in Drupal. I love the testing frameworks available in Rails.
You see, Cucumber for Rails allows you to write your tests in English (or something reasonably close to it). For example:
Feature: Contributor In order to maintain security As a contributor I want to be able to edit existing submissions Scenario: Contributor should not be able to create or delete submissions Given I am a company contributor And there is a 2010 survey for "Company X" When I view the dashboard Then I should not be able to delete a submission And I should not be able to create a submission
Putting that in my features/contributor.feature" file and executing that with =bundle execute cucumber features/contributor.feature
gets me a lovely test with green signs all around.
You’re thinking: Rails is awesome, but it’s not that awesome, is it? How can it know about the specifics of the application?
Rails knows because I’ve written my own step definitions for Cucumber. Step definitions are simple. You can define them with a regular expression like this:
When /^I view the dashboard/ do visit root_path end Then /^I should not be able to create a submission/ do page.should_not have_button("Create submission") end
You can also define steps that parse arguments from the string or call other steps:
Given /^there is a ([^ ]+) survey for \"([^\"]+)\"$/ do |year,name| @company = Company.find_by_name(name) assert !@company.nil? Given "there is a #{year} survey" end
You can even take multi-line input, such as tables.
Automated testing is so awesome!