How We Run Cucumber
Cucumber is a wonderful behavior driven development tool by Aslak Hellesøy. There is a getting started guide in the wiki at github that describes how to get it set up and running.
We’ve written a wrapper around Cucumber to help make it easier to run along with our application and to make it less intrusive when it runs the browser (at least under Linux).
Server Execution
Most of our test driven development doesn’t require script/server to be running the web application, and we want it to run under either the cucumber or test rails environment when it does. Stopping (if it’s running) the development server, starting it and then shutting it down again when the tests are done was a manual process that we automated.
Xnest
When we run Cucumber under X Windows, it often grabs focus and keeps us from doing anything else with the desktop while the tests are running. This is annoying to say the least. Thankfully X11 has a utility called Xnest which allows you to run a window which is a contained X desktop. Running this and then telling the browser to run inside it keeps it out of our way and allows us to keep using the machine without being constantly interrupted by the browser constantly jumping to the foreground.
script/server Arguments
To pass arguments (such as the port, or other options) through to script/server, put a -- between the arguments to script/cucumber-runner and they will be passed on verbatim to script/server. In this example, -p 8080 will be passed to script/server instructing it to use port 8080.
$ script/cucumber-runner -g 1024x768 -- -p 8080
cucumber-runner
#!/usr/bin/env ruby
require 'optparse'
# Controller for running Cucumber feature tests on your Rails application.
# Supports stopping/starting WEBRick in cucumber or test rails environment and
# (on supporting systems, eg: Linux) running the browser under Xnest to keep it
# away from your other desktop activities.
#
#
# Author:: Kyle Burton <kyle.burton@gmail.com>
# Copyright:: Copyright (c) 2010 Kyle Burton
# License:: Distributes under the same terms as Ruby
#
# Command line runner.
#
class CucumberRunner
# location of the rails scripts
SCRIPT_ROOT = File.dirname(__FILE__)
# Set up defaults, can be overridden with command line parameters.
def initialize
@opts = {
:env => 'cucumber',
:geometry => '1280x800',
:display => ENV['DISPLAY'],
:xnest_display => ':2',
:control_webrick => true,
:try_use_xnest => true
}
end
# Determine if Xnest is present, and if it should be used (Not on OS X).
def use_xnest?
return false unless @opts[:try_use_xnest]
on_darwin = (`uname` =~ /Darwin/)
has_xnest = !(`which Xnest`.empty?)
!on_darwin && has_xnest
end
# Start Xnest in the background, save off the pid so it can be stopped later.
def start_xnest
@opts[:display] = @opts[:xnest_display]
cmd = "Xnest #{@opts[:xnest_display]} & echo $!"
@xnest_pid = `#{cmd}`.to_i
end
# Stop Xnest with a SIGTERM.
def stop_xnest
Process.kill("TERM", @xnest_pid) if @xnest_pid
end
# Stop the WEBRick server by looking for it in the process tree.
def stop_webrick
res = `ps aux | grep [r]uby | grep [s]cript/server`
pid = res.split[1]
return unless pid
puts "#{$0} STOPPING WEBRick pid=#{pid}"
Process.kill "KILL", pid.to_i
end
# Start WEBRick with the configured rails environment as a daemon (background).
def start_webrick
cmd = "#{SCRIPT_ROOT}/server -e #{@opts[:env]} -d"
puts "#{$0} Starting WEBRick: #{cmd}"
system cmd
end
# Process any command line arguments.
def parse_opts
OptionParser.new do |opts|
opts.banner = "Usage: #{$0} [options]"
opts.on("-h", "--help") do
puts <<-EOH
#{$0} [[opts]]
-e ENV --envrionment ENV Rails environment to run under default=#{@opts[:env]}
-g GEO --geometry GEO Xnest geometry to use default=#{@opts[:geometry]}
-X --no-xnest Do not use Xnest (even if present)
-d DSP --display DSP DISPLAY to use default=#{@opts[:display]}
-x DSP --xnest-display DSP Xnest's DISPLAY to use default=#{@opts[:xnest_display]}
-W --no-webrick Don't start WEBRick (assume running) default=false
EOH
exit 0
end
opts.on("-e", "--envrionment ENV") do |env|
@opts[:env] = env
end
opts.on("-g", "--geometry GEO") do |geo|
@opts[:geometry] = geo
end
opts.on("-X", "--no-xnest") do
options[:use_xnest] = false
end
opts.on("-d", "--display DSP") do |dsp|
options[:display] = dsp
end
opts.on("-x", "--xnest-display DISP") do |disp|
options[:xnest_display] = disp
end
opts.on("-W", "--no-webrick") do
options[:control_webrick] = false
end
end.parse!
end
# Process options, start Xnest, [re]start WEBRick, execute the cucumber
# suite, then stop Xnest and stop WEBrick
def run
parse_opts
start_xnest if use_xnest?
if @opts[:control_webrick]
stop_webrick
start_webrick
end
cmd = "#{SCRIPT_ROOT}/runner #{SCRIPT_ROOT}/cucumber #{ARGV}"
ENV['DISPLAY'] = @opts[:display]
ENV['RAILS_ENV'] = @opts[:env]
puts "#{$0} using RAILS_ENV=#{ENV['RAILS_ENV']}"
res = system cmd
ensure
stop_webrick if @opts[:control_webrick]
stop_xnest if @xnest_pid
end
def self.main
self.new.run
end
end
CucumberRunner.main
You can download or check out cucumber-runner from my github cucumber-example project.
Running Cucumber with this wrapper helps make it easier and less intrusive to use. If anyone has suggestions for how to make it less intrusive while running under OS X, please email me, I’d love to hear your suggestions.