Acceptance Testing for Omeka Plugins

For the month of December, I’m going to be heads-down on NeatlineFeatures (project page; Github). This is an Omeka plugin that lets people associate geo-spatial metadata with Omeka items by drawing on a map.

Before I started coding, I wanted to make sure I knew what I was doing, so I wrote a few user stories and passed them around for comment. Part of the value of user stories is that they are expressed in short, natural language statements, but they can also be transitioned into acceptance tests that everyone has had a voice in.

(I should mention that I’m really just trying out user stories. They seem like a good idea in theory, but we’ll have to see how it works in practice.)

When testing Omeka plugins, I use Omeka’s unit testing framework (PHPUnit). I don’t see a reason to change that. However, unit testing frameworks generally aren’t a good fit for acceptance tests. They are both too focused and low-level and sometimes don’t have a great way of acting like a browser. A bigger problem is that they shut non-coders out of the loop. Having an English-y way of expressing tests helps to involve everyone working on the project, not just the developers.

For the Praxis Program, we’ve been talking about using Cucumber for testing. I thought this would be a good time to try it out.

I expected this would be painful.

Fortunately, I was wrong.

About the System

The tests will be driven by Cucumber. Since this is in Ruby, they won’t interact directly with Omeka (there is cuke4php, but I’m not going there). Instead, everything will take place through the browser. Here’s how the system breaks down:

Cucumber will read in the tests and execute them. It provides the language that we use to write the tests and the code we use to implement them.

Capybara defines a DSL for interacting with the browser. We’ll use this when we define actions or steps for the tests.

selenium-webdriver allows Capybara, Cucumber, or any Ruby code to talk to the browser.

Selenium is a system for writing tests that run in the browser. It has a Firefox plugin, which we’ll use today for actually doing the tests.

Omeka, PHP, and MySQL are all running in a VM, managed by Vagrant. (See this post for how to set up the system.)

Rake is used to control the system.

Adding Ruby

Most of these tools are in Ruby, so the first step is to mix Ruby into the Omeka/PHP plugin project. To manage Ruby, I use RVM, so I added a .rvmrc file to switch to the right version of Ruby and make sure all the right gems are installed:

rvm use 1.9.3
bundle install

The gems are listed in a Gemfile:

source :rubygems
gem 'rake'
gem 'cucumber'
gem 'capybara'
gem 'selenium-webdriver'

That’s it. Now, when I change to the plugin directory, Ruby and the gems I need are available.

Setting up Cucumber

Cucumber expects a specific directory structure. I created that with these Bash commands:

mkdir features
mkdir features/step_definitions
mkdir features/support

Cucumber also needs a configuration file in features/support/env.rb:

require 'selenium-webdriver'
require 'capybara'
require 'capybara/cucumber'
require 'capybara/dsl'
Capybara.app_host = 'http://features.dev'
Capybara.run_server = false
Capybara.default_wait_time = 15
Capybara.default_driver = :selenium

Adding Features

Cucumber groups tests into features. Each feature is in a separate file, and each contains one or more scenarios.

For a contrived example, I tested logging into into the Omeka admin console.

Feature Files

The feature file for this is easy to read and understand, by design. I put this into features/login.feature:

Feature: AdminLogin
  In order to make changes to the site
  As the site administrator
  I want to be able to log into the admin console

  Scenario: Login
    Given I visit the admin page
    And I enter "features" for the "Username"
    And I enter "features" for the "Password"
    When I press "Log In"
    Then I should see a page title of "Omeka Admin:"
    And I should see a header of "Dashboard"

That’s it. I could have added a scenario for not authenticating correctly or other cases, but I won’t worry about that right now.

Step Files

Feature files are great for people, but Cucumber/Ruby still doesn’t know what to do with it. To fill that gap, I defined what to do for each step in the scenario in a step file. I put this into features/step_definitions/login_steps.rb:

Given /^I visit the admin page$/ do
  visit('/admin')
end

Given /^I enter "([^"]*)" for the "([^"]*)"$/ do |value, label|
  fill_in(label, :with => value)
end

When /^I press "([^"]*)"$/ do |button|
  click_on(button)
end

Then /^I should see a page title of "([^"]*)"$/ do |page_title|
  find(:xpath, '//title').has_content?(page_title)
end

Then /^I should see a header of "([^"]*)"$/ do |header|
  find(:xpath, '//h1').has_content?(header)
end

(It would be better to group the step definitions into files by task or domain or some other way than one-step-file-per-feature-file, but for this demonstration, this is fine.)

Step definitions tell Cucumber what to do for each test. Inside each definition, I used Capybara commands that tell the browser what to do or check the page that the browser’s looking at. These commands use Selenium to actually drive the action, but I don’t have to worry about that.

Running Tests

We have a couple of steps left to see actual tests being run. First, we could use the cucumber command, but we’ll probably have other things to automate (PHPUnit tests, I’m looking at you), so we’ll go ahead and create a Rakefile that runs the Cucumber tests. This is easy to do, since Cucumber ships with some rake tasks.

Put this into Rakefile:

require 'cucumber/rake/task'

task :default => :cucumber

Cucumber::Rake::Task.new do |t|
  t.cucumber_opts = %w{--format pretty}
end

Now, as I mentioned before, the Omeka site is running in a Vagrant-managed VM. Start it up:

vagrant up

Once the VM’s up, run the tests by just calling rake. You’ll see Firefox start up and close down, and at the end, you should see something like this (you may want to set the video to full screen):

Cucumber-Omeka from Eric Rochester on Vimeo.

My interests include text processing, text mining, and natural language processing, as well as web-development and general programming. Studied medieval English literature and linguistics at UGA. Dissertated on lexicography. Now I program in Haskell and write when I'm not building cool stuff for the Scholars' Lab. Also, husband and parent. Do you notice that sleep…

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Archives