Cucumber is an end-to-end approach to testing, which means it uses a website in the same way as a human would (i.e. by navigating to pages and clicking on things). It’s basically like clicking through the website to check things are working as they should, except a computer does the grunt work for you. I'll say now I’m by no means an expert when it comes to Rails testing (far from it), however in learning the basics I’ve found there’s a lot information out there which can be overwhelming for a beginner - it certainly was for me. So to that end so I’ve put together a quick rundown of how to get started and some of the key concepts. Here's what we'll cover:
Before we get stuck in, I’m assuming you’ve got a Rails project already set up you want to test. Also make sure you have a test database set up in
config/database.yml, and that it's not the same one as your development database. The test database will be wiped every time we run our tests so this is important.
First we need to install some gems so we can run our tests. Do this by adding the following to your
# Gemfile group :test do gem 'cucumber-rails', :require => false gem 'database_cleaner' gem 'capybara' gem 'selenium-webdriver' end
Install the gems by running:
Next, run the Cucumber generator. This will set up a bunch of files and folders for you.
rails generate cucumber:install
To run tests in Chrome rather than Firefox (the selenium default), you'll need to install Chromedriver. On OSX you can do this via Homebrew:
brew install chromedriver
Then add the following to the bottom of your
Let's go through how the tests are structured and the various files involved.
There are two main types of file which make up a Cucumber test: feature files and step definitions. Feature files contain human readable tests, whereas step definitions translate these features into actions a server or browser can perform.
Both these file types, along with a couple of other supporting files, are held in a folder called
/features in the root of your Rails project. These folders are automatically generated by
rails generate cucumber:install you ran above. By way of example, say you had a contact form on your site you wanted to test - the folder structure might look something like this:
/features /step_definitions contact_form_steps.rb /support env.rb contact_form.feature
In this example,
contact_form.feature contains the scenarios you want to test, and
step_definitions/contact_form_steps.rb contains the ruby code which will make those scenarios actually do something. You need to manually created these feature and step definition files when making new features. Let's go through what each one does in a bit more detail:
Features are text files with a
.feature extension, written in a syntax called Gherkin. Gherkin is the language you’ll use to describe what you want your tests to do. You’ll then write Ruby code to translate the features you write in Gherkin to something a computer understands. A very simple example feature file might look something like this:
# features/contact_form.feature Feature: Contact form Scenario: Send an email via the contact form Given I am on the contact page When I fill in the contact form Then I should see a thank you message
The Gherkin syntax is geared around the "Given, When, Then" format. The idea is that writing tests this way gives you a consistent template for writing easy to understand test criteria. It's a subject worthy of it's own post, but for now you can find more information on the thinking behind it over on the Cucumber Wiki.
Step definitions are Ruby files which interpret your Gherkin steps. As mentioned above, they take a sentence a human can understand and turn it into something a computer can understand. For example, to translate the above scenario, the step definitions could look something like this:
# features/step_definitions/contact_form_steps.rb Given(/^I am on the contact page$/) do visit('/contact') end When(/^I fill in the contact form$/) do fill_in('Message', :with => 'Hello there!') find('Submit').click end Then(/^I should see a thank you message$/) do page.has_content?("Thank you") end
The language we’re using to make this work is called Capybara. With it you can visit urls, find and interact with page elements, assert that elements have content - basically do anything a person would do when they use a website. There’s a helpful cheat sheet on Github with a rundown of the basic tasks.
Tests are run via the command line. There are a few different ways to run tests.
To run all your scenarios in one go, use the following:
bundle exec cucumber
To just run one specific scenario, you can refer to it by name. So for our example scenario above you could run:
bundle exec cucumber -n "Send an email via the contact form"
Needless to say this is much quicker than running all your tests every time and is very useful in active development.
A small footnote, if you're using the foreman gem to load environment variables, you should prepend
foreman run to your test invocations, e.g:
foreman run bundle exec cucumber -n "Send an email via the contact form"
You can also just include tags for a single Scenario. This is useful if you only need to open a browser for one scenario in a feature.
When you run your tests you'll see a summary explaining the outcome of your test, which will look something like the following:
Given I am on the contact page When I fill in the contact form Then I should see a thank you message 1 scenario (1 passed) 3 steps (3 passed) 0m10.242s
As you can see, the output will tell us which of our steps passed and how long the test took. Also if there are errors they'll pop up here with handy line numbers so we've got somewhere to start debugging from.
This is just skimming the surface of testing your code but hopefully it's enough to get started with. There'll be more in this series on how to handle test data and when to write tests in your workflow, but to begin with it's helpful just to write a couple of tests on an existing project to get a feel for how they work. Once you feel the satisfaction of having a test pass, you'll be hooked.
Neither do I. You're busy, and so is your inbox. I'll only be in touch when I publish something new. And of course it goes without saying your email will be kept completely private.