Continuous testing with Guard, RSpec, and Cucumber
The Guard gem watches for when you modify code or test files, and automatically re-runs tests that could be affected by those changes immediately, so you get instant feedback if you just broke something. It’s a great tool for supporting true TDD but a bit tricky to set up.
Add to the test
and development
groups in your Gemfile
and then
rerun bundle install
:
group :test, :development do
gem 'guard'
gem 'guard-rspec', require: false
gem 'guard-cucumber'
gem 'guard-shell'
end
Run guard init rspec
and then guard init cucumber
to populate an
initial Guardfile
, and add that file to your repo.
Guard works with plugins that tell it how to integrate with different
testing tools. In the Guardfile
, the blocks named group rspec
,
group cucumber
, etc. name the different plugins and tools. Within
each plugin’s block, there are one or more blocks
guard :
tool, :cmd =>
_command-to-run-tests
that have the structure:
watch(
regexp matching filenames) { _tests to run when those files change_ }
If you look at the default provided block for Rspec, you should be able to discern the following rules:
-
When a controller file changes, run all specs for that controller
-
When helper files change, run all specs
-
When routes file(s) change, run all route specs
-
When
application_controller.rb
changes, rerun all controller specs (since all controllers inherit fromApplicationController
)
Basically you are telling Guard which tests may cover functionality in the files that changed.
Start up Guard by running bundle exec guard
. Make a trivial change
to one of your project files to make a test fail (e.g. introduce a
syntax error), and watch Guard re-run the matching specs.
Running only a subset of specs
In the :cmd
argument to guard :rspec
block, note the option
:failed_mode => :focus
. This means: If one or more specs failed as
a result of the most recent test run, on future runs try only those
failed specs, until they pass; then go back to running all affected
specs.
To make this work, we have to do two things. First, we have to tell
RSpec to enable focus mode, in which only specs annotated with
:focus => true
are run. In spec/rails_helper.rb
, add in the RSpec
configuration block:
config.filter_run :focus => true
config.run_all_when_everything_filtered = true
Then, when Guard has just run some tests and hit a failure, annotate a
single example (it "does something" do...end
) or a group of examples
(describe "something" do...end
) with :focus => true
. The next
time you change a file that might affect these specs, only the specs
so annotated will be run.
When those specs go back to passing, remove :focus => true
and the
next Guard-triggered run will re-run all affected specs.