测试时我应该在 Factory girl 中还是在规范文件中存根模型?
Posted
技术标签:
【中文标题】测试时我应该在 Factory girl 中还是在规范文件中存根模型?【英文标题】:Should I stub the model in Factory girl or in the spec file while testing? 【发布时间】:2012-02-22 17:55:32 【问题描述】:我遇到的几乎每个规范文件最终都会编写如下内容:
before :each do
@cimg = Factory.build :cimg_valid
@cimg.stub(:validate_img).and_return true
@cimg.stub(:validate_img_url).and_return true
@cimg.stub(:save_images).and_return true
@cimg.stub(:process_image).and_return true
@cimg.stub(:img).and_return true
end
我的意思是,我从 Factory.build 获得的模型是完全有效的。但是,如果我不存根那些东西,它会将东西保存在文件系统中,并验证我没有测试的东西......
我的意思是,我认为这样做会更干净:
before :each do
@cimg = Factory.build :cimg_for_testing_tags
end
如果在工厂内存根甚至是可能的。
存根模型的正确方法是什么?
【问题讨论】:
【参考方案1】:@fkreusch 的答案在您使用新的 RSpec expect()
语法 (3.0+) 之前效果很好
将其放入 rails_helper.rb
对我有用:
FactoryBot::SyntaxRunner.class_eval do
include RSpec::Mocks::ExampleMethods
end
在 OP 的示例中,您现在可以这样做:
FactoryBot.define do
factory :cimg_for_testing_tags do
... # Factory attributes
after(:build) do |cimg|
allow(cimg).to receive(:validate_img) true
end
end
end
来源:github.com/printercu,参见:https://github.com/thoughtbot/factory_bot/issues/703#issuecomment-83960003
【讨论】:
执行此处描述的操作现在会出现以下错误(FactoryGirl v4.7.0):The use of doubles or partial doubles from rspec-mocks outside of the per-test lifecycle is not supported.
@jsears 我遇到了这个错误,因为我的rails_helper.rb
在before(:suite)
块中运行FactoryGirl.lint
,并且无法在那里设置存根。我通过将 lint 调用包装在 RSpec::Mocks.with_temporary_scope ...
中解决了这个问题。
请注意,FactoryGirl
现在是 FactoryBot
,因此在您的示例中这两个名称应该更改。【参考方案2】:
在最新版本的 factory_girl 中,你有一个 after_build 回调,所以我相信你可以这样定义你的工厂:
FactoryGirl.define do
factory :cimg_for_testing_tags do
... # Factory attributes
after_build do |cimg|
cimg.stub(:validate_img).and_return true
end
end
end
更新
factory_girl 3.3.0 之后,语法改为:
FactoryGirl.define do
factory :cimg_for_testing_tags do
... # Factory attributes
after(:build) do |cimg|
cimg.stub(:validate_img).and_return true
end
end
end
【讨论】:
但是我应该这样做吗?还是应该在规范文件中存根? 我认为,如果您重复自己很多次,那么在这种情况下使用通用存根是有意义的,只需确保 :cimg_for_testing_tags 有一个父工厂,在您想要的情况下没有存根测试实际行为。 这是一个很棒的技术。我发现自己在为这种情况寻找解决方案而苦苦挣扎。谢谢@fkreusch! 这不再有效。在最新的 rspec 中,这将导致失败"Using 'stub' from rspec-mocks' old ':should' syntax without explicitly enabling the syntax is deprecated."
不幸的是,如果您切换到使用新的 rspec allow()
语法,您会遇到不同的问题,因为 FactoryGirl 不包含 RSpec 的方法:NoMethodError: undefined method 'allow' for #<FactoryGirl::SyntaxRunner:0x007f95469cc0d8>
。有谁知道适用于最新版本的解决方案?
您可以使用def cimg.validate_img; true; end
并在没有 rspec 的情况下有效地将其存根。【参考方案3】:
工厂应该生产“真实世界”的对象,因此在工厂中改变行为(即存根)是一种不好的做法(并且容易出错)。
你可以的
let(:user) instance_double(User, FactoryGirl.attributes_for(:user))
before do
allow(user).to receive(:something).and_return('something')
end
如果您的 before
子句太大,您可能需要将其提取到单独的方法中,或者创建一个模拟子类来覆盖您要存根的方法。
【讨论】:
【参考方案4】:您也可以考虑使用FactoryGirl#build_stubbed。
【讨论】:
以上是关于测试时我应该在 Factory girl 中还是在规范文件中存根模型?的主要内容,如果未能解决你的问题,请参考以下文章
如果在描述块中调用 Factory Girl 为啥会创建重复项
Rails 4 使用 Engine 中的 Factory Girl 工厂