【问题标题】:How can I share the factories that I have in a GEM and use it in other project?我如何分享我在 GEM 中的工厂并在其他项目中使用它?
【发布时间】:2015-10-20 10:16:07
【问题描述】:

我有一个包含一些工厂的宝石。宝石看起来像:

.
├── 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

现在我通过添加类似gem 'core', git: 'https://url.git' 的东西在另一个Ruby 项目(Grape)中使用gem。

现在一切正常,因为我可以使用 Grape 项目中的 User 模型。

但是我想使用工厂 (users),这样我就可以为 Grape 项目编写进一步的集成测试。

在 Grape 项目中,spec_helper.rb 看起来像:

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

现在我的测试“users_spec.rb”看起来像:

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

现在,当我尝试使用 rspec spec/api/users_spec.rb 运行测试时,我得到:

我不断收到此错误:

 Failure/Error: user = build(:user)
 ArgumentError:
   Factory not registered: user

任何帮助将不胜感激,因为我一直在为此而苦苦挣扎。

【问题讨论】:

  • 啊!很高兴看到一些规格,,:)
  • 虽然有可能。您是否应该分享规格是值得怀疑的。您应该只使用 gem 提供的内容。并且规格应该适合您的应用程序,因此您不需要工厂。

标签: ruby-on-rails ruby rspec gem factory-bot


【解决方案1】:

另一个答案中建议的require-ing 每个工厂文件的替代方法是更新FactoryBot.definition_file_paths 配置。

在定义工厂的 gem 中:

创建一个解析工厂路径的文件:

# lib/my_gem/test_support.rb

module MyGem
  module TestSupport
    FACTORY_PATH = File.expand_path("../../spec/factories", __dir__)
  end
end

在您的应用程序/gem 中使用来自其他 gem 的工厂:

# 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

definition_file_paths 解决方案的优势在于,FactoryBot.reload 等其他功能将按预期工作。

【讨论】:

    【解决方案2】:

    问题是您可能没有在加载路径中公开规范文件夹(以及工厂)。一般来说,这是正确的做法。检查你*.gemspec,你可能有类似的东西:

    s.require_paths = ["lib"]
    

    这意味着只有lib 目录下的文件才能被使用您的gem 的其他项目所需要。见http://guides.rubygems.org/specification-reference/#require_paths=

    因此,要解决您的问题,您需要在 lib 文件夹中放置一个文件,该文件夹“知道”您的工厂在哪里并需要这些文件。所以在你的情况下,创建一个文件lib/<your gem name>/factories.rb 并添加:

    GEM_ROOT = File.dirname(File.dirname(File.dirname(__FILE__)))
    
    Dir[File.join(GEM_ROOT, 'spec', 'factories', '*.rb')].each { |file| require(file) }
    

    在另一个项目中加载工厂:

    require '<your gem name>/factories'

    对我来说很好用。我唯一还没有弄清楚的是如何命名你的工厂。不确定工厂女孩是否允许这样做。

    【讨论】:

    • Dir[File.join(GEM_ROOT, 'spec', 'factories', '**','*.rb')].each { |file| require(file) } 这将包括子文件夹中的工厂
    • GEM_ROOT = Gem.loaded_specs[gem_name].full_gem_path
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-17
    相关资源
    最近更新 更多