我正在尝试使用Rspec和FactoryBot在Rails中测试我的模型。我正在使用let!
:
let!(:account1) { create(:account, :year) }
let!(:account2) { create(:account, :three_months) }
let!(:account3) { create(:account, :month) }
let!(:account4) { create(:account, :day) }
我正在测试我的作用域是否返回正确的记录数组。我的假设是,还应该有一些“坏数据”,以测试范围是否不返回它不应该返回的东西。例如:
describe ".seen_last_two_months" do
subject { Account.seen_last_two_months.to_a }
it { is_expected.to eq([account3, account4]) }
end
看来,当测试量增加时,速度会显着下降。似乎每个调用let!
的测试都会命中数据库,从而创建一个新记录。
答案 0 :(得分:1)
- 我设置测试的方式是否正确,那么我是否还要测试查询不希望返回的记录?
醇>
是的,只是你应该。
- 有没有办法只调用一次创建记录?
醇>
是的,您需要创建这些记录来测试特定范围。因此,只应针对该特定测试调用它们。您可以将它们移动到与范围测试相关的# Keep this one without `!`, so it will be called (in other tests), if and when needed
let(:account1) { create(:account, :year) }
describe ".seen_last_two_months" do
let!(:account1) { create(:account, :year) }
let!(:account2) { create(:account, :three_months) }
let!(:account3) { create(:account, :month) }
let!(:account4) { create(:account, :day) }
subject { Account.seen_last_two_months.to_a }
it { is_expected.to eq([account3, account4]) }
end
块,然后不会为其他测试调用它们。
before(:all)
<强>更新强>
如果您只想为所有测试创建一次记录,请改用let
。看起来在before(:all)
块中调用before(:all) do
@account1 = create(:account, :year)
@account2 = create(:account, :three_months)
@account3 = create(:account, :month)
@account4 = create(:account, :day)
end
describe ".seen_last_two_months" do
subject { Account.seen_last_two_months.to_a }
it { is_expected.to eq([@account3, @account4]) }
end
定义的变量是一个坏主意,而是使用实例变量:
account*
在测试中将所有@account*
替换为{{1}}。
请记住,对象中任何测试所做的更改也会反映在下一个测试中。
答案 1 :(得分:0)
您可以创建一次所有帐户并测试它们上的所有范围。只需在it
块下移动所有内容,如下所示:
context "scopes" do
it 'selects accounts correctly' do
let!(:account1) { create(:account, :year) }
let!(:account2) { create(:account, :three_months) }
let!(:account3) { create(:account, :month) }
let!(:account4) { create(:account, :day) }
expect(Account.seen_last_two_months.to_a).to eq([account3, account4])
expect(Account.another_scope.to_a).to eq([account1, account2])
expect(Account.one_more_scope.to_a).to eq([account2])
end
end
但是这种规范更难维护,您需要在实例中指定许多不同的属性来检查所有范围。我只对类似的范围使用这种方式,例如按状态显示范围(&#39;活动&#39;,&#39;非活动&#39;,&#39;存档&#39;)。
顺便说一句:提供更具描述性的名称总是一个好主意,比如let!(:year_ago) { create(:account, :year) }