A parallel test runner specifically for rspec.
The main difference between this and similar gems is that it spawns entirely new worker processes instead of forking. This makes configuring the workers easier (especially when Rails is involved) as many things will "just work".
It's intended to work with RSpec >= 3.2. It may work with earlier versions, but I doubt it.
Put it in your Gemfile, bundle, and you're away.
gem 'rspec-queue'
If you need isolated databases, you'll need to ensure they are prepared before attempting to run any tests.
Add any configuration needed for each worker to your spec_helper
file.
RSpecQueue::Configuration.after_worker_spawn do |index|
# Establish connection to an isolated database
ActiveRecord::Base.configurations['test']['database'] << index.to_s
ActiveRecord::Base.establish_connection(:test)
end
Running tests via rspec-queue is the same as running them via rspec.
bundle exec rspec-queue spec
By default, rspec-queue will spawn a number of workers equal to one less than the count of your total cpus. You can override this behaviour by setting the RSPEC_QUEUE_WORKERS
environment variable.
RSPEC_QUEUE_WORKERS=6 bundle exec rspec-queue spec
If you're doing some form of acceptance testing you'll probably want to use xvfb to isolate the browsers for each worker so they don't do annoying things like steal focus from each other. This can cause many headaches trying to debug strange failures!
Fortunately, there's a gem for that: https://github.com/leonid-shevtsov/headless
You can then add some extra configuration in the after_worker_spawn
block to use a different display for each worker:
RSpecQueue::Configuration.after_worker_spawn do |index|
# ...
Headless.new(display: 100 + index.to_i, reuse: true, destroy_at_exit: true).start
end
If you're using Rails with page caching in test, you probably want to isolate the public folders for each worker. This should probably be done in your test environment configuration. It should be as easy as making a copy of your public folder for each worker.
# test.rb
Rails.application.configure do
# ...
# RSPEC_QUEUE_WORKER_ID is a unique identifier for the current worker
if ENV["RSPEC_QUEUE_WORKER_ID"]
# copy the public directory to a distinct folder
master_public_path = Rails.root.join("public")
worker_root_path = Rails.root.join("tmp", "rspec-queue", ENV["RSPEC_QUEUE_WORKER_ID"])
FileUtils.mkdir_p worker_root_path
FileUtils.cp_r master_public_path, worker_root_path
worker_public_path = worker_root_path.join("public")
# point rails to the new directory
config.paths["public"] = worker_public_path
config.action_controller.page_cache_directory = worker_public_path
end
end
Setting a distinct public folder can also assist with issues that arise when uploading files in acceptance tests.
The way the formatting works isn't great. It was hacked together in a rush and extracted from an existing codebase as is. It unfortunately means that this gem won't work with any formatter that isn't it's own. The way the formatter is set in the rspec-queue binary is also not ideal and will likely cause issues with certain setups.
At the moment, the worker passes some lo-fi results to the server over the unix socket, but not the full set of example results that most formatters use and expect. To deal with this we use our custom formatter that only needs basic information.
However, if we want to use another formatter, we would need to reconstruct much more information, which is difficult to marshal/unmarshal, and if we try to do this manually we risk coupling ourselves to a particular rspec version's internals.
The plan is to fix that so it will work just fine with any formatter and make the configuration more sensible, but right now, it is how it is.
MIT license.