rails - 由 FactoryGirl 保留的对象在控制器中不可用



我正在管理员命名空间中为我的控制器编写测试。使用 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,2)中,他们说这可能是由于DatabaseCleaner策略,应该使用truncation而不是transaction策略。我这样做是因为Mongoid只允许truncation.而且我也没有使用支持 JavaScript 的测试,并特别告诉 rspecuse_transactional_fixtures = false

FactoryGirl 和 DatabaseCleaner 的 RSpec 配置:

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

最新更新