Automatically Run Rspec When Plain-Old Ruby (Not Rails) Files Change

Automatically run RSPec when plain-old Ruby (not Rails) files change

Like David said, Guard can be used to watch a wide variety of files and perform actions when those files are modified. It does not have to be used with a Rails app. I have set up something similar in the past using guard. Here is what I did:

Place the following in your Gemfile:

source 'https://rubygems.org'

gem 'guard'
gem 'guard-shell'
gem 'rspec'
gem 'rb-fsevent', '~> 0.9'

Then run:

$ bundle install

Create a Guardfile in your home directory with:

$ guard init

In the Guardfile, comment out the examples and add this:

guard :shell do
watch(%r{^*\.rb}) { `bundle exec rspec spec/` }
end

This tells guard to watch for modifications to any ruby files in the directory and execute the command bundle exec rspec spec/ when they change (the backticks are used to execute the command in the shell).

Then open up a new terminal window in your current directory and start a guard server to start watching the files:

$ bundle exec guard

Now your Rspec test suite should automatically run when you modify ruby files in the directory.

Tests do not run when file changes with Guard and rspec on windows

I'm not a Windows user and this is not from my personal experience, but as a Guard maintainer I often hear that the fchange gem has its problems. You can force Guard polling for changes and thus skip fchange with:


bundle exec guard -p

Maher Sallam has addressed this issue and created wdm, which seems to be more reliable. There's also a pull request for integrate it into Guard. I recommend you to test the integration and give Maher some feedback from a real world Windows user, since Maher is a Linux guy :P

Questions about setting up a working Guard-RSpec example project

I'll answer the question in the title and cover the "sub-questions" as I go.

  1. The best way to set up a project (as of now) is to use bundle exec guard --init rspec. This should give reasonable defaults to start work immediately. It's not perfect, but there is a lot of work planed to improve things, so do ask questions on GitHub instead (makes more sense).

  2. Guard has to maintain backward compatibility, so there are some "non-intuitive" things for now and skimming through all the docs first (and wiki) is a good investment to quickly know what's available and where. Asking when confused or in doubt is also a good idea (one issue per question is best).

  3. Guard uses a DSL to simplify setting up listeners. This is a bit non-intuitive and clunky at times, but it does help organize actions into groups, which can help maintain complex workflows. The DSL's command for e.g. clearing the terminal automatically is: (clearing: on). (This answers question 3).

  4. There are all kinds of uses and scenarios, so Guard tries hard to make everyone happy and on every platform too. Guard uses Listen, which watches directories recursively (due to restrictions on OSX mostly). This usually isn't a problem, but for huge directions on OSX this can be very, very slow. That's why Guard lets you select which top directories to watch (like 'lib', 'app', etc.). Watching the whole project directory is very convenient, so that is still the default. More info on this is at the Listen project. So by default all directories (:directories statement) are "physically watched" (take up operating resources), though in Guard you only configure which changes you want to respond to (which is what watch statements do).

  5. The words chosen are a bit misleading at times. E.g. watch in the DSL actually means: "out of all the changes happening, select changes matching ...". The block passed to watch is given the results of the match. That block should return a list of files for the current guard plugin to run. So "watch" probably is more misleading than helpful. "match" would probably be a better choice and it might replace "watch" in the future.

  6. The guard-rspec project runs RSpec on changed files. You can see the exact RSpec commands if you run guard with the debugging option on, e.g. bundle exec guard -d. To simplify setup, Guard::RSpec uses a DSL that should work out-of-the-box if your project follows a given setup. E.g. dsl.watch_spec_files_for(ruby.lib_files) is defined here: so it pretty much already should do what you want if you put all your tested source files in lib. For other folders, you can add your own. E.g. Rails projects typically have sources also in an app directory, so in the default Guard::RSpec template there's an statement: dsl.watch_spec_files_for(rails.app_files) with the pattern defined as: rails.app_files = %r{^app/(.+)\.rb$} If you have a typical case that isn't covered, open an issue in that project. (covers question 2).

Everything looks fine in the example project and suggestions are mostly based on taste or preference. E.g.

  • Instead of let (:greeter) { Example::RSpecGreeter.new }, I'd use RSpec's implicit subject (but some may argue that it's less explicit and less readable)
  • if you're testing Example::RSpecGreeter, I'd recommend putting that class in a separate file and including it instead (require 'example/rspec_greeter')
  • you might add RubCop/Guard::RuboCop for detecting convention issues (covers 4th question)
  • you might want to check out Guard's own Guardfile used to test itself for a more "real-life" setup without the documentation clutter.
  • for best results I think it's best to copy a whole existing project and rename the parts you want to change. Usually there are many hours spent still fine-tuning things like alternate RSpec configs for Travis, special gem release tasks, certain workarounds and conveniences, etc.

Set up RSpec to test a gem (not Rails)

I've updated this answer to match current best practices:

Bundler supports gem development perfectly. If you are creating a gem, the only thing you need to have in your Gemfile is the following:

source "https://rubygems.org"
gemspec

This tells Bundler to look inside your gemspec file for the dependencies when you run bundle install.

Next up, make sure that RSpec is a development dependency of your gem. Edit the gemspec so it reads:

spec.add_development_dependency "rspec"

Next, create spec/spec_helper.rb and add something like:

require 'bundler/setup'
Bundler.setup

require 'your_gem_name' # and any other gems you need

RSpec.configure do |config|
# some (optional) config here
end

The first two lines tell Bundler to load only the gems inside your gemspec. When you install your own gem on your own machine, this will force your specs to use your current code, not the version you have installed separately.

Create a spec, for example spec/foobar_spec.rb:

require 'spec_helper'
describe Foobar do
pending "write it"
end

Optional: add a .rspec file for default options and put it in your gem's root path:

--color
--format documentation

Finally: run the specs:

$ rspec spec/foobar_spec.rb

rspec - bug when I try to run multiple files including one that has a line-number?

Upgrade to a newer version of rspec, for example version 2.14.8+

How do you run a single test/spec file in RSpec?

Or you can skip rake and use the 'rspec' command:

bundle exec rspec path/to/spec/file.rb

In your case I think as long as your ./spec/db_spec.rb file includes the appropriate helpers, it should work fine.

If you're using an older version of rspec it is:

bundle exec spec path/to/spec/file.rb

rspec filter with tag - do not run code in `describe`

My final solution is not elegant, but get job done effectively (thanks @noname for pointing me for direction of solution)

I create a new rake task, that filter files with specified tag and after that create subprocess to run only filtered specs (and like rspec --fail-fast fails on first failure (as I need it)

like this

  files_with_tag = `grep -Ril spec/ -e ':mytag'`.split("\n")
files_with_tag.each do |current_file|
result = `rspec #{current_file} --tag mytag`
puts(result)
exit unless result.include?('0 failures')
end


Related Topics



Leave a reply



Submit