Testing with Cucumber, Capybara and Selenium

In a prior post, I talked about using Capybara and Selenium as just a few among many tools. In a related post on using RSpec and Capybara, I brought up the possibility that “the natural language parts are, in fact, the executable code.” This was in reference to the idea of code logic expressed as natural language in RSpec but that still required actual code that sounded almost like the natural language statements. Wouldn’t it be nice if you didn’t have to write it twice? You just write it one way and then it executes? The argument then might be to just write the code, and assume the intent of the test can be explained via comments or something else. But many people really wanted to keep the focus on natural language tests.

I brought up how Cucumber is one such tool that does try to make natural language statements directly executable. Tools like Cucumber are often presented in the context of Behavior-Driven Development (BDD) environments, where the goal is to allow various people to specify tests — even though some don’t like to call them tests — in a concise format that can be directly automated.

So let’s take a look at using Cucumber as an overlay to RSpec and Capybara.

I will be doing this example in the context of testing a user interface and not in relation to a Rails application. I bring this up specifically because as many testers look at these tools, they are often presented with a lot of information that may make it hard to see how to apply them in different contexts. A fairly good example of this would the post Integration Testing with RSpec, Capybara, and Selenium. This is not a comment on that particular blog post since I think it’s very insightful and useful. That post does, however, assume a context that many testers are simply not involved in.

For this example, you’ll need Ruby and Rubygems installed on your system. You’ll also need the rspec, selenium-webdriver and capybara gems installed.

First, create a project directory called spec. Then, from that directory, create some more directories:

$ mkdir test_specs
$ mkdir test_specs/test_definition
$ mkdir test_specs/engine

As a note for those of you who know Cucumber, you may say that my directory structure is “wrong.” Just bear with me. I’m doing this for a purpose.

In the root of the project directory, create a file named cucumber.yml and put the following contents in it:

default: -r test_specs/engine/ -r test_specs/test_definition test_specs

Here I’m just requiring specific files to be loaded. Any Ruby (*.rb) files will be loaded from the engine and test_definition subdirectories. Since I don’t have a features directory (which Cucumber looks for by default), I include ‘test_specs’ at the end to indicate which directory Cucumber should look in for any specification files.

In the test_specs\engine directory, create a file named env.rb and put the following code logic in it:

This env.rb file is the Cucumber equivalent of spec_helper.rb file that you might create if you are using RSpec. Really all you need to know at this stage is that when you run Cucumber, it will look for this file in the directory structure you specified in cucumber.yml — in our case, test_specs — and load the env.rb file first. For my purposes, I’m just requiring all the necessary logic and setting Capybara’s default test driver to Selenium, since I want to run my tests via a browser interface.

In the test_specs directory, create a file named youtube_search.feature. Put the following in the file:

Feature: YouTube has a search function.

  Given I am on YouTube

Scenario: Search for a term
  When I fill in "search_query" with "text adventure"
  And I press "search-btn"
  Then I should see "GET LAMP: The Text Adventure Documentary"

Wait, what language is that? The above is, strictly speaking, a programming language. The language that operates behind the scenes of Cucumber — and that requires feature files to have the above format — is known as Gherkin.

I should note that Cucumber normally looks for a features directory. Here I’ve chosen to call this directory test_specs, mainly just to show that you can. The file just created is what Cucumber calls a feature file — and what I prefer to call a test specification — and contains the description of what I want to achieve by testing the feature. Without worrying about the detail of the file, let’s just run Cucumber and see what happens. At the project directory, execute the following command:

$ cucumber

You should see that Cucumber runs and your output will say something like this:

1 scenario (1 undefined)
4 steps (4 undefined)

You’ll see a lot of other information as well. What the above is telling you is that you had one scenario (“Search for a term”) and four steps (one in the Background and three in the Scenario itself). All of those steps were undefined, however, so Cucumber couldn’t run a thing. Cucumber tries to helpfully provide what it calls “step definitions” that would be used to allow execution of the steps.

Now, in the test_specs/test_definition directory, create a file named youtube_search_steps.rb and put the following code logic in it:

Cucumber would expect this kind of file in a step_definitions directory that it finds under a features directory. I prefer the term test_definition to match the idea of a test_specification. Again, I did this just to show that you can structure Cucumber in a way that matches your language or test organization preferences.

One thing to note is that you will sometimes modify the test (step) definitions from what Cucumber has recommended. For example, Cucumber recommended I should add this:

What I put in place was instead:

Taking Cucumber’s advice, I “expressed the regexp with the code I wished I had.” Specifically, I added a regular expression to let this particular test definition be a little more dynamic.

I should note at this point that my Cucumber feature (test specification) file is actually showcasing some pretty bad Cucumber practices but I did this on purpose to show how many testers, as they start out learning these tools, tend to take implementation steps that they would normally use in an automated testing solution and translate them up to Cucumber. You may say, “So what’s wrong with that?” Well, keep in mind that Cucumber is meant to be the part of your tool set that captures the intent of your tests and not the implementation details for those tests have to work. While that’s easy to say, it’s sometimes a struggle for testers to truly make that separation.

Anyway, let’s run again:

$ cucumber

If all goes well, you should see Firefox pop up and run through the scenario. (One reason this might not work is if the Firefox browser’s executable is not available on your path.) The output should ultimately say this:

1 scenario (1 passed)
4 steps (4 passed)

What doing all this should have proved to you is that Cucumber, Capybara, and Selenium do work on your system. This also gave you a bare bones idea about how to go about using the tools in a non-Rails, user interface-focused test. So now let’s concentrate on that intent versus implementation concept. First, let’s change the feature/test specification a bit:

Scenario: Search for a term
  When I search for "text adventure"
  Then I should see "GET LAMP: The Text Adventure Documentary"

Here the filling in of a specific text field and the clicking of a specific button have been rolled up into a statement of intent, which is essentially “I can search for stuff.” Specifically, “When I search for {some phrase}.” I’ve basically refactored the statement to speak more to the intent of the test without bringing in too many implementation details. The Then statement really didn’t need refactoring as it was.

This modified statement requires me adding a test definition to serve as a matcher for the new phrase:

Try running Cucumber again to make sure it all still works. It should.

And that’s about it! A very high level introduction but that was sort of the point. Incidentally, let’s say you wanted to replace your test driver with yet another tool called Mechanize. First you have to make sure to grab the gem capybara-mechanize. Then modify the env.rb file with the following lines:

Now you can run Cucumber again and you are using mechanize.

I should note that you might get an error about a (Gem::LoadError). The specifics will depend entirely on the version numbers of your gems. As an example, one time I was told “Unable to activate capybara-mechanize-0.2.7, because capybara-1.0.0 conflicts with capybara (~> 0.4.0).” The problem was I had two Capybara’s in my gem list. The capybara-mechanize gem only worked with the older version, not the newer one. The problem was that other gems (like the version of Cucumber I had!) would only work with the newer Capybara. Welcome to the world of Ruby and gem incompatibilities. I can’t offer much advice about these kinds of things; just know they are possible. My point with showing you mechanize was just to show that you could change the test driver but still execute the same test specification (feature file) with the same test (step) definitions.

My goal in this post was not to teach Cucumber and most certainly not to teach Capybara, Selenium or even how to write effective logic when using these tools together. Rather, I just wanted to have a fairly concise tutorial that shows how testers can use these tools at all, particularly outside of Rails and with a focus on system-level UI testing rather than integration testing.


This article was written by Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.

7 thoughts on “Testing with Cucumber, Capybara and Selenium”

  1. Hi Jeff,

    Thanks a lot for your wonderful Story. I really felt as if I am reading a story (As oppossed to the confusing technical blogs :-).

    I am very new to Cucumber world and after reading your story I got confidence on ramping up on this tool fast.

    Please send me if you have any other info on Cucumber, Capybara and Selenium combination by which I can practice..

    My Question:
    I want to learn on how to manage the web site URL in a separate file other than the ‘youtube_search_steps.rb’ file in your example, can you suggest me on how I can do that?

  2. It turns out that the test works perfectly without

    require ‘rspec/expectations’

    in env.rb. What was the reason to include it?

    1. Good point. There probably was no reason to include that. I think I was including that out of habit. I tend to want to use RSpec expectations for checking the state of tests.

  3. Selenium-cucumber is a behavior driven development (BDD) approach to write automation test script to test web applications.
    It enables you to write and execute automated acceptance tests of web apps.
    It is cross-platform, open source and free.
    Automate your test cases with minimal coding.
    Code efficient and time efficient.
    Get well formatted test reports.
    All you need is selenium-cucumber gem.
    You can find Source code here.

    1. Thanks for referencing your gem, Sameer. I’m one of those people who personally tends to not like Selenium over Watir or Capybara. However, that said, I think there’s a lot of value for people providing frameworks, libraries or engines that include Selenium more directly. I’ll definitely be checking out your GitHub repo.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.