Testing Rails 3 generators with RSpec
Rails provides an easy way to test generators if you’re using test/unit, but what can you do if you’re using RSpec?
class InstallGeneratorTest < Rails::Generators::TestCase
tests InstallGenerator
destination File.expand_path("../../tmp", __FILE__)
setup :prepare_destination
test "Generates an initializer" do
run_generator
assert_file "config/initializers/mygem.rb"
end
end
You don’t really want to use test unit just to test generators. One approach is to use cucumber to drive aruba through the actions of generating a new Rails app, running bundle install, running your generator then verifying it did the right thing. The problem with this approach is that it’s really, really slow. At least it was a few months ago when I tried it. bundle install isn’t exactly known for it’s speed, though technically that’s not bundlers fault.
It depends on the functionality you’re testing, but for the actions that most generators perform like adding files to a project, running it in a separate process with Aruba, generating a fresh rails app and running bundle install seems like overkill. You get more assurance that it will work that way, because it’s a full stack integration test doing the same thing the user will do, it’s just going to be slow. The approach Rails::Generators::TestCase takes is to simply run the generator in the current process against a temporary directory. There are trade off’s whichever way you choose, but for the average generator I’d settle for less integration and more SPEED!
Today I released generator_spec for testing generators with RSpec. It’s basically a thin wrapper around Rails::Generators::TestCase, with the same assertions and setup methods available. It comes with an awesome file matcher DSL too.
require "generator_spec/test_case"
describe InstallGenerator do
include GeneratorSpec::TestCase
destination File.expand_path("../../tmp", __FILE__)
before do
prepare_destination
run_generator
end
specify do
destination_root.should have_structure {
no_file "non_existant.rb"
directory "config" do
directory "initializers" do
file "mygem.rb" do
contains "# Change this"
end
end
end
directory "db" do
directory "migrate" do
migration "create_tests" do
contains "class TestMigration"
end
end
end
}
end
end
More information can be found with the code on Github.