rails - FactoryGirl 保留的对象在 Controller 中不可用

rails - Objects persisted by FactoryGirl are not available in Controller

我正在为管理命名空间中的控制器编写测试。使用 RSpec (3.5.0)、FactoryGirl (4.8.0)、DatabaseCleaner (1.5.3) 和 Mongoid (6.0.3)。

问题是这些测试行为很奇怪。在测试 GET index 请求时,FactoryGirl 生成的对象已成功创建并持久化。但是,控制器似乎没有找到它们。

我有三个不同的控制器。三分之二的人有这个问题,第三个就像一个魅力。代码是相同的(除了命名)唯一的区别是工作控制器的资源是嵌套的。

配饰作品:

describe "GET #index", get: true do

    let (:accessory) { FactoryGirl.create(:accessory) }

    before do
      get :index, params: { category_id: accessory.category_id.to_s }, session: valid_session, format: :json
    end

    it "responses with OK status" do
      expect(response).to have_http_status(:success)
    end

    it "responses with a non-empty Array" do
      expect(json_body).to be_kind_of(Array)
      expect(json_body.length).to eq(1)
    end

    it "responses with JSON containing accessory" do
      expect(response.body).to be_json
      expect(json_body.first.with_indifferent_access).to match({
          id: accessory.to_param,
          name: 'Test accessory',
          description: 'This is an accessory',
          car_model: 'xv',
          model_year: '2013',
          images: be_kind_of(Array),
          category_id: accessory.category.to_param,
          dealer_id: accessory.dealer.to_param,
          url: be_kind_of(String)
        })
    end
  end

而类别的则没有:

describe "GET #index", get: true do

    let (:category) { FactoryGirl.create(:category) }

    before do
      get :index, params: {}, session: valid_session, format: :json
    end

    it "responses with OK status" do
      expect(response).to have_http_status(:success)
    end

    it "responses with a non-empty Array" do
      expect(json_body).to be_kind_of(Array)
      expect(json_body.length).to eq(1)
    end

    it "responses with JSON containing category" do
      expect(response.body).to be_json
      expect(json_body.first.with_indifferent_access).to match({
          id: category.to_param,
          name: 'Test category',
          image: be_kind_of(String),
          url: be_kind_of(String)
        })
    end
  end

如您所见,逻辑是相同的:在 before 挂钩中发出请求并使用 let 设置对象。

另一个奇怪的事情是 GET show 测试具有相同逻辑的类别非常有效。

在这些问题 (1, ) 中,他们说这可能是由于 DatabaseCleaner 策略,应该使用 truncation 而不是 transaction 策略。我这样做是因为 Mongoid 只允许 truncation。而且我也没有使用启用 JavaScript 的测试,并特别告诉 rspec 到 use_transactional_fixtures = false

RSpec FactoryGirl 和 DatabaseCleaner 的配置:

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods

  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each, :js => true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end
end

我能够通过发出请求并在每个示例中创建一个对象来使这些测试通过,而不是使用 beforelet。但我认为它应该适用于他们。

控制器索引方法是默认的:

def index
  @thing = Thing.all
end

你对这种奇怪的行为有什么想法吗?

请尝试 let! 而不是 let

请注意 let 是惰性求值的。类别数据在您调用 category.to_param 时生成。 before块中不存在。

另见 https://relishapp.com/rspec/rspec-core/v/3-5/docs/helper-methods/let-and-let