We are a software consultancy based in Berlin, Germany. We deliver
high quality web apps in short timespans.

Upstream Agile GmbH

Kickstart Rspec with Spork

July 27, 2009 by alex

For doing Red/Green TDD it is essential to have fast running tests. But no matter how fast your tests are, there are always these seconds when you and your pair are sitting in front of the screen waiting that the test run actually starts. That is the time when Rails, your code, gems and plugins are loaded. In a rather small project, which I use as an example here, this cumulates into a start up time of around 5s before EACH test run. This becomes even longer when your project grows.

..... Finished in 0.127571 seconds 5 examples, 0 failures real 0m6.456s user 0m4.682s sys 0m1.681s

Although 5s, as in my example, aren’t such a long time, it sums up to a significant amount when doing Red/Green TDD. So everything that helps you to cut down test startup times, increases your productivity. AutoSpec or Rspactor approach this on the user site by running your test as soon as you change something. But they won’t cut down the technical implied start up time. Spec-server tried to approach the load time issue first by loading the Rails stack including the libraries of your environment upfront in an extra process. It uses Drb to get your test code to the pre-loaded testing process. Although the idea behind spec-server is the right one, it never worked for me in day to day usage. I came in situations in which tests failed or code wasn’t reloaded properly at all. But recently I discovered spork thanx to Rany (@purzelrakete). Spork takes the idea from spec-server and learned from its mistakes. E.g. it has its own class loading mechanism that takes care of not preloading your models at startup, instead of relying on rails auto loading. Beside working more reliable, this is also an option for other frameworks but Rails. It just works! Running the same test code than before with spork (spec paht_to_spec --drb), cuts the startup time into half.

..... Finished in 0.066628 seconds 5 examples, 0 failures real 0m3.588s user 0m0.469s sys 0m0.108s

When doing 200 test startups a day, a number which is not unrealistic, consider doing it Red/Green, this a 10 min time win :) You probably won’t need more than 10 min to set up spork.

  1. Install spork

gem install spork

  1. Bootstrap your Rails app

cd /path/to/project/root spork --bootstrap

This command adds some instructions and code to spec/spec_helper.rb. Basically two blocks, one to tell which code to preload and one to tell which to reload on every test run. Code outside these blocks is run at both times.

  1. Modify spec/spec_helper.rb

  2. Modify spec/spec.opts

Add --drb to spec/spec.opts so that rake spec uses drb to communicate with spork. Set TM_RSPEC_OPTS --drb in TextMate so that the rspec TextMate bundle uses drb as well.

  1. Fire up spork for rspec

spork rspec

  1. Kickstart your RSpec Tests

If you find out that some of your code wasn’t reloaded properly, spork -d shows you which classes are loaded and where from. There shouldn’t be any of your app/classes in it. If that’s the case, the reason for this can be either a eager plugin (e.g. older versions of thinking_sphinx) or you used your code in initializers or the environment. Put such code in spork blocks like these in your spec_helper for the testing environment, this will prevent wrong preloading.

Here is an example how the spec_helper could look like:

require 'rubygems'
require 'spork'

ENV["RAILS_ENV"] = "test"

Spork.prefork do
  require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
  require 'spec'
  require 'spec/rails'
  require 'machinist/active_record'
end

Spork.each_run do
  require 'spec/blueprints'
end

Oh and btw, you can use spork for Cucumber as well, just modify cucumbers env.rb (same as you did with your spec_helper) and then launch spork with spork cucumber

And one last thing, as we are talking about faster test cycles, take a look at parallel _specs, to run your specs on multiple cores.

Happy TDDing!