Setting Up Cucumber for your Rails Projects

Written by: Clemens Helm
6 min read

https://fast.wistia.com/embed/medias/dkm3uxg7u3.jsonphttps://fast.wistia.com/assets/external/E-v1.js

This is the 15th Testing Tuesday episode. Every week we will share our insights and opinions on the software testing space. Drop by every Tuesday to learn more! Last week we showed you how to set up RSpec with standalone Ruby applications and Rails web applications.


Set up Cucumber for Ruby applications

For all Ruby applications you can use the cucumber gem. In the screencast we walk you through creating a basic Ruby project and installing cucumber using bundler. We implement one passing scenario and make Cucumber use RSpec expectations instead of Minitest that ships with Ruby.

Set up Cucumber for Rails web applications

There is a special cucumber-rails gem that makes setting up Cucumber with Ruby on Rails web applications even easier. It contains a generator that prepares your app by adding preconfigured cucumber profiles, rake tasks and a Cucumber script. We'll look into the advantages in more detail in the screencast.

Up next Testing Tuesday: JavaScript Testing with Jasmine

Next week we'll show you how to test your Javascript with Jasmine. In the meantime check out our other episodes on Cucumber. You can find a list of them below in the "Further info" section.

Further info:

Transcript

Setting up Cucumber

Ahoy and welcome! My name is Clemens Helm and this is Codeship Testing Tuesday #15. Last week I showed you how to set up RSpec for Ruby and Rails projects. This week we're gonna do the same thing for Cucumber. Thanks to Rafael who left me a comment and showed me an even faster way of setting up RSpec for a new project. I'll use your technique in this episode.

We're gonna set up one standalone Ruby application and one Rails application, because there are a few differences in the setup. Let's get started with the standalone application first:

Let's create an empty directory cucumber-app for our application. cd cucumber-app In the directory we initiate bundler by calling bundle init. This will create a Gemfile for us. Let's add the Cucumber gem gem "cucumber" and install it by running bundle.

When we run cucumber now, it tells us "No such file or directory - features". Cucumber will look for our features in the "features" directory, so let's create it mkdir features and run cucumber again. It ran successfully without executing any features. Let's add a simple feature: mate ., create features/warm_welcome.feature

Feature: Warm welcome
  In order to make my users feel comfortable on my website
  As the website owner
  I want to greet them appropriately
  Scenario: Greeting a sailor
    Given I am a sailor
    Then I want to be greeted "Ahoy and welcome!"

Running cucumber lists the missing step definitions. Let's copy these snippets into a file "sailor_steps.rb" features/step_definitions/sailor_steps.rb:

Given(/^I am a sailor$/) do
  @user = User.new type: :sailor
end
Then(/^I want to be greeted "(.*?)"$/) do |greeting|
  @user.greeting.should == greeting
end

Now cucumber tells us that it doesn't know the constant User. Let's add a user class in lib/user.rb. Cucumber still complains, because we need to require user.rb somewhere. Let's do that in the "sailor_steps.rb" file require "user"

We get a different error message now, because the user's constructor doesn't accept any arguments yet. But how did Cucumber know where to look for the User class? We didn't eplicitly tell it to look in the lib directory. Like I already showed you in last week's episode, there's a global variable that contains the load paths of source files. When we print this variable in our Cucumber steps puts $: it will list our "lib" directory as first entry of the load paths. Cucumber added this directory, because there's a convention to put your Ruby classes there.

Ok, let's remove the puts statement again. Cucumber complained about our constructor, so let's make it accept a "type" argument:

def initialize type: type
end

Now Cucumber still misses the "greeting" method.

def greeting
end

And now Cucumber complains that it doesn't know the method "should". The reason is that Cucumber doesn't contain the RSpec matchers. By default, you can use "Minitest" which is included in the Ruby standard library. We could rewrite our step definition as:

Then(/^I want to be greeted "(.*?)"$/) do |greeting|
  assert_equal @user.greeting, greeting
end

This will give us the expected result. But how can we stick with our RSpec syntax? (undo change)

We have to install "rspec-expectations". Let's add them to our Gemfile. gem "rspec-expectations" bundle cucumber And now our feature runs on RSpec. Great! Let's fix the error by greeting our sailor correctly:

def greeting
  "Ahoy and welcome!"
end

Now our feature works!

But what if we want to greet sailors on our Rails web application as well? Let's create a new Rails application for this. rails new rails-greeter We could use the cucumber gem here as well, but there is a special cucumber-rails gem that comes with additional goodies for Rails. Let's add it to the test-environment in our Gemfile:

cd rails-greeter mate .

group :test do
  gem 'cucumber-rails', require: false
end

We added require: false so Cucumber isn't loaded when we run other testing tools like RSpec. The cucumber command will require the cucumber gem anyway. It's also recommended to add the "database_cleaner" gem to your Gemfile. Database cleaner makes sure that your database is cleaned after every scenario.

group :test do
  gem 'cucumber-rails', require: false
  gem 'database_cleaner'
end

Let's install these gems with Bundler. bundle install

Cucumber-Rails provides us with a generator script to set up cucumber. We only need to run rails generate cucumber:install.

This will do a few things:

  • It creates a cucumber.yml file. This defines 3 cucumber profiles: default, work in progress and rerun. You can run cucumber with each of these profiles by passing the --profile option. For example, if we run the "wip" profile, it will run scenarios tagged with "@wip" and complain, if there are more than 3 of them. You can customize the options for these profiles or add your own profiles in this file.

  • It also creates a cucumber script. In Rails 4 this actually belongs in the "bin" directory, so let's move the file and delete the "script" directory. This script makes sure that the right cucumber distribution is required.

  • The install script also adds directories for features, step definitions and support files and already creates the first support file "env.rb" which contains the Cucumber configuration.

  • And it creates a rake file to run cucumber as a rake task. rake -T | grep cucumber There are several tasks to run only subsets of your features. In general I recommend against using them though, because rake increases the load time for cucumber.

  • It modifies the database.yml and creates an own cucumber enviroment which inherits from the test environment by default.

I won't go into detail about how to write your features again, because it works the same way as for other Ruby applications. So the main advantage of the cucumber-rails gem is that it hooks directly into our rails application by creating everything that's necessary with the installation script.

Outro

If you haven't already, I highly recommend you to try Cucumber. The setup is very easy and I personally love working with it. In the next few days we'll review the book "Cucumber Recipes" which offers a Cucumber solution for almost every problem. Don't miss out on that! See you next Testing Tuesday when we'll take a look at Javascript testing with Jasmine. And please remember: Always stay shipping!

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.