RSpec 2 add-on for specifying and testing generators
This project contains RSpec 2 matchers, helpers and various utilities to assist in writing Generator specs. There is additional support for writing specs for Generators in Rails 3.
Why?
Rails 3 has a Rails::Generators::TestCase class for use with Test-Unit, to help test generators. This TestCase contains specific custom assertion methods that can be used to assert generator behavior. To create an RSpec 2 equivalent, I wrapped Rails::Generators::TestCase for use with RSpec 2 and created some RSpec 2 matchers that mimic the assertion methods of the Test-Unit TestCase. I have also a bunch of "extra goodies" to the mix.
This RSpec DSL should make it very easy and enjoyable to spec and test your Generators with RSpec 2 :)
Feedback
Please let me know if you find any issues or have suggestions for improvements.
Install
gem install generator-spec
The gem is a jewel based on jeweler. To install the gem from the code, simply use the jeweler rake task:
rake install
Usage
The following demonstrates usage of this library. There are many more options and DSL convenience methods (see wiki, code or specs).
Configuration
First setup the spec_helper.rb. Here is an example configuration.
# spec/spec_helper.rb
require 'rspec'
require 'generator-spec'
# configure it like this to use default settings
RSpec::Generator.configure do |config|
config.debug = false
config.remove_temp_dir = true
config.default_rails_root(__FILE__)
config.logger = :stdout # :file to output to a log file, logger only active when debug is true
end
# or customize the location of the temporary Rails 3 app dir used
RSpec::Generator.configure do |config|
# ...
config.rails_root = '~/my/rails/folder'
end
Specs for generators
I recommend having a separate spec file for each generator (generator specs). You can use the special require_generator statement to ensure that one or more generators are loaded and made available for a given spec.
require_generator :canable
This will load the generator : generators/canabale_generator.rb
If the generator is in a namespace (subfolder of generators), use a nested approach like this:
require_generators :canable => ['model', 'user']
This will load the generators: generators/canable/model_generator.rb
and generators/canable/user_generator.rb
You can also load generators from multiple namespaces and mix and match like this. I recommend against this however as it is difficult to read.
require_generators [:canable => ['model', 'user'], :other => :side, :simple]
Auto-require all generators
You can also require all generators or all within a specific namespace like this:
require_generators :all require_generators :canable => :all
Example: full generator spec
# spec/generators/model_generator_spec.rb
require 'spec_helper'
# list of generators to spec are loaded
require_generator :canable
describe 'model_generator' do
# include Rails model helpers for ActiveRecord
# available:
# Other ORM options - :mongo_mapper, :mongoid and :data_mapper
# note: use_orm auto-includes the :model helper module
use_orm :active_record
# load helper modules and make available inside spec blocks
# here the module in rails_helpers/rails_migration is included
# to load multiple helpers use the method - use_helpers
use_helper :migration
before :each do
# define generator to test
setup_generator 'model_generator' do
tests Canable::Generators::ModelGenerator
end
# ensure clean state before each run
remove_model :account
end
after :each do
# ensure clean state after each run
remove_model :account
end
describe "the weird stuff!!!" do
before :each do
@generator = with_generator do |g|
g.run_generator :account.args
end
end
it "should not work without an existing Account model file" do
@generator.should_not generate_file :account, :model
end
end
it "should not work without an existing Account model file" do
with_generator do |g|
g.run_generator :account.args
g.should_not generate_file :account, :model
end
end
it "should decorate an existing Account model file with 'include Canable:Ables'" do
with_generator do |g|
create_model :account
g.run_generator 'account'.args
g.should generate_model :account do |content|
content.should have_class :account do |klass|
klass.should include_module 'Canable::Ables'
end
end
end
end
end
Code specs
There are a bunch of specialized ruby code matchers in the matchers/content folder which can be used to spec code files in general. Check out the specs in spec/generator_spec/matchers/content for examples on how to use these.
Rails specs
The rails_helpers folder contains a bunch of files which makes it easy to spec rails files and to perform various "Rails mutations". These mutations make it easy to setup the temporary Rails app in a specific pre-condition, which is required for a given spec.
Examples: Rails helpers
require File.expand_path(File.dirname(FILE) + '/../../../spec_helper')
describe 'controller' do include RSpec::Rails::Controller
before :each do
create_controller :account do
%q{
def index
end
}
end
end
after :each do
remove_controller :account
end
it "should have an account_controller file that contains an AccountController class with an index method inside" do
Rails.application.should have_controller :account do |controller_file|
controller_file.should have_controller_class :account do |klass|
klass.should have_method :index
end
end
end
end
Note on Patches/Pull Requests
- Fork the project.
- Make your feature addition or bug fix.
- Add tests for it. This is important so I don't break it in a future version unintentionally.
- Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
- Send me a pull request. Bonus points for topic branches.
Copyright
Copyright (c) 2010 Kristian Mandrup. See LICENSE for details.