I have a gem that includes some Factories. The gem looks something like:
.
├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── db
├── lib
│ ├── models
│ │ ├── users.rb
├── pkg
├── core.gemspec
├── spec
│ ├── factories
│ │ └── users.rb
│ ├── fixtures
│ ├── helpers
│ ├── integration
│ ├── spec_helper.rb
│ ├── support│ │
│ └── unit
│ └── users_spec.rb
└── tasks
Now i'm using the gem in another Ruby project (Grape) by adding something like gem 'core', git: 'https://url.git'
.
Now everything is working fine as I can use User
model from Grape project.
However I want to use the factories (users
) so I can write further integration tests for Grape project.
In Grape project, in spec_helper.rb
it looks like:
require 'rubygems'
require 'bundler/setup'
Bundler.require(:default, :development)
ENV['RACK_ENV'] ||= 'test'
require 'rack/test'
require File.expand_path('../../config/environment', __FILE__)
RSpec.configure do |config|
config.mock_with :rspec
config.expect_with :rspec
config.raise_errors_for_deprecations!
config.include FactoryGirl::Syntax::Methods
end
require 'capybara/rspec'
Capybara.configure do |config|
config.app = Test::App.new
config.server_port = 9293
end
Now my test 'users_spec.rb' looks like:
require 'spec_helper'
describe App::UsersController do
include Rack::Test::Methods
def app
App::API
end
describe "/users/me" do
context "with invalid access token" do
before(:each) do
get "/api/v2/users/me"
user = build(:user)
end
it 'returns 401 error code' do
expect(last_response.status).to eq(401)
expect(user).to eq(nil)
end
end
end
end
Now when I try to run the test using rspec spec/api/users_spec.rb
I get :
I keep getting this error:
Failure/Error: user = build(:user)
ArgumentError:
Factory not registered: user
Any help would be appreciated as I've been struggling for this.
The problem is that you probably don't expose the spec folder (and herewith the factories) in the load path. Which, in general, is the right thing to do. Check you *.gemspec
, you probably have something like:
s.require_paths = ["lib"]
This means only files under the lib
directory can be required by other projects using your gem. See http://guides.rubygems.org/specification-reference/#require_paths=
So to solve your problem, you'd need to place a file inside the lib
folder which 'knowns' where your factories are and requires those. So in you case, create a file lib/<your gem name>/factories.rb
and add:
GEM_ROOT = File.dirname(File.dirname(File.dirname(__FILE__)))
Dir[File.join(GEM_ROOT, 'spec', 'factories', '*.rb')].each { |file| require(file) }
In the other Project load the factories with:
require '<your gem name>/factories'
Works fine for me. The only thing I havn't figured out yet is how to namespace your factories. Not sure if factory girl allows this.
An alternative to require
-ing each factory file as suggested in the other answer, is to update the FactoryBot.definition_file_paths
configuration.
Create a file which will resolve the factory path:
# lib/my_gem/test_support.rb
module MyGem
module TestSupport
FACTORY_PATH = File.expand_path("../../spec/factories", __dir__)
end
end
# spec/spec_helper.rb or similar
require "my_gem/test_support"
FactoryBot.definition_file_paths = [
MyGem::TestSupport::FACTORY_PATH,
# Any other paths you want to add e.g.
# Rails.root.join("spec", "factories")
]
FactoryBot.find_definitions
The advantage of the definition_file_paths
solution is that other functionality like FactoryBot.reload
will work as intended.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With