A Ruby on Rails Engine does not come with Rspec. The setup is simple which you can find below along with instructions for adding Factory Bot.
Generate an engine
Lets generate a new engine. We typically like to have an engines folder so we will generate our new engine there.
rails plugin new engines/my_feature --mountable --skip-test --dummy_path=spec/dummy
--skip-tests option because we plan on using Rspec instead of MiniTest. We also are specifying the dummy path to create a dummy application for our specs to use.
Add and Configure Rspec
Next step is to add Rspec. Navigate to your engine’s gemspec file. In our case it is located at
engines/my_feature/my_feature.gemspec. Complete all of the TODO’s.
Add our development dependency for rspec.
At this point, you should be able to bundle install from your engine.
root/engines/my_feature $ bundle install
root/engines/my_feature $ rails g rspec:install create .rspec exist spec create spec/spec_helper.rb create spec/rails_helper.rb
If you try to run rspec now, you will likely run into a Load Error. This is because the
rails_helper is trying to require an environment file from the engines root. Our environment file is located within our dummy app.
# require File.expand_path('../../config/environment', __FILE__) require File.expand_path('../dummy/config/environment', __FILE__)
You can confirm rspec is installed by running it
$ rspec spec/ Finished in 0.00037 seconds (files took 0.05945 seconds to load) 0 examples, 0 failures
Now it is time to add some tests. Let’s generate a
User model so we can test.
root/engines/my_feature $ rails g model User invoke active_record create db/migrate/20190406181424_create_my_feature_users.rb create app/models/my_feature/user.rb
Notice that a spec file for
User was not generated. To get that setup we will configure our generators in our
Destroy the user model
root/engines/my_feature $ rails d model User invoke active_record remove db/migrate/20190406181424_create_my_feature_users.rb remove app/models/my_feature/user.rb
module MyFeature class Engine < ::Rails::Engine isolate_namespace MyFeature config.generators do |g| g.test_framework :rspec end end end
User which should include a spec
root/engines/my_feature $ rails g model User invoke active_record create db/migrate/20190406182129_create_my_feature_users.rb create app/models/my_feature/user.rb invoke rspec create spec/models/my_feature/user_spec.rb
Depending on how you manage your migrations, you may also need to set the migration path to be scoped to our dummy application.
ENGINE_ROOT = File.join(File.dirname(__FILE__), '../') begin ActiveRecord::Migrator.migrations_paths = File.join(ENGINE_ROOT, 'spec/dummy/db/migrate') ActiveRecord::Migration.maintain_test_schema! ...
Create and migrate your test database if you have not already already
root/engines/my_feature $ rails db:create db:migrate RAILS_ENV=test
root/engines/my_feature $ rspec spec/ Finished in 0.0061 seconds (files took 2.6 seconds to load) 1 example, 0 failures, 1 pending
Hopefully you see one pending test for our User spec.
Add Factory Girl
Last step, we are going to add factory girl. We will need to make a few changes to get this working. First, add another development dependency to our gemspec.
root/engines/my_feature $ bundle install
Revisit our configuration change to our
engine.rb. Modify the block to include factory_bot.
config.generators do |g| g.test_framework :rspec g.fixture_replacement :factory_bot g.factory_bot dir: 'spec/factories' end
We need to ensure our factories will be loaded when we run our test suite. Open the rails helper and add the following:
require 'factory_bot_rails' FactoryBot.definition_file_paths << File.join(File.dirname(__FILE__), 'factories') FactoryBot.find_definitions
Rspec also needs to include factory bot methods so we can do things like
build(:user) in our tests. That can be done by including the methods in our Rspec configure block.
RSpec.configure do |config| ... config.include FactoryBot::Syntax::Methods ...
Next time you generate a model, you should also have a new factory.
root/engines/my_feature $ rails g model Car invoke active_record create db/migrate/20190406184550_create_my_feature_cars.rb create app/models/my_feature/car.rb invoke rspec create spec/models/my_feature/car_spec.rb invoke factory_bot create spec/factories/my_feature/cars.rb root/engines/my_feature $ rails db:drop db:create db:migrate RAILS_ENV=test
Car factory is generated in
The factory bot generator might not have name-spaced the class so be sure to check.
factory :my_feature_car, class: 'MyFeature::Car'
Open the car spec and add a test.
it 'should create a car' do car = create(:my_feature_car) expect(MyFeature::Car.count).to eq(1) end
Run rspec and we should see a passing car spec.
root/engines/my_feature $ rspec spec/ Finished in 0.01697 seconds (files took 3.78 seconds to load) 2 examples, 0 failures, 1 pending
I hope this helped you get rspec setup in your rails engine. As you create more engines, you might start to find these steps repetitive. In a future post, we will explore different ways to reduce the need of the boilerplate configuration.
Found this useful? Know how it can be improved? Get in touch and share your thoughts at