如何使用冗余的 `let!` 方法调用来干燥 RSpec 测试?
How to DRY up RSpec tests with redundant `let!` method calling?
我如何在我的 Rails 应用程序中使用 RSpec:
这样的测试块
describe "POST create" do
describe "if we have a logged in user and he can be an owner" do
describe "and if params are valid" do
let!(:service_attributes_with_categories_1_and_2) {
FactoryBot.attributes_for :service_with_categories_1_and_2
}
let!(:category_1) { FactoryBot.create :category, {id: 1} }
let!(:category_2) { FactoryBot.create :category, {id: 2} }
it "creates a new service" do
# ...
end
it "creates associations with categories" do
# ...
end
end
describe "and if categories are not valid" do
# ...
end
describe "and if some common service params are not valid" do
# ...
end
end
describe "if no user is logged in, but params are valid" do
let!(:service_attributes_with_categories_1_and_2) {
FactoryBot.attributes_for :service_with_categories_1_and_2
}
let!(:category_1) { FactoryBot.create :category, {id: 1} }
let!(:category_2) { FactoryBot.create :category, {id: 2} }
it "doesn't create a new service" do
# ...
end
it "doesn't create associations with categories" do
# ...
end
end
describe "if logged user cannot be an owner, but params are valid" do
let!(:service_attributes_with_categories_1_and_2) {
FactoryBot.attributes_for :service_with_categories_1_and_2
}
let!(:category_1) { FactoryBot.create :category, {id: 1} }
let!(:category_2) { FactoryBot.create :category, {id: 2} }
it "doesn't create a new service" do
# ...
end
it "doesn't create associations with categories" do
# ...
end
end
end
如我们所见,我有很多冗余的 let!
方法调用,但我不知道如何让它变干。我不能只定义普通方法,因为那样的话,变量将只在这个方法的范围内可用。我也不能让我的类别在一般范围内创建,因为在两种情况下,由于测试性质,它们不应该被创建。那么,我应该如何在技术上做到这一点?
最后我决定将 FactoryBot.create
函数拆分为两个步骤:FactoryBot.build
和 .save
函数 运行 在获得的对象上。它允许我将我的 let!
调用移动到主范围,并定义方法,它在我需要的情况下准确地保存我构建的对象。我的 DRY 代码现在看起来像这样:
describe "POST create" do
let!(:service_attributes_with_categories_1_and_2) {
FactoryBot.attributes_for :service_with_categories_1_and_2
}
let!(:category_1) { FactoryBot.build :category, {id: 1} }
let!(:category_2) { FactoryBot.build :category, {id: 2} }
def save_categories_1_and_2
category_1.save
category_2.save
end
describe "if we have a logged in user and he can be an owner" do
describe "and if params are valid" do
before(:each) do
save_categories_1_and_2
end
it "creates a new service" do
# ...
end
it "creates associations with categories" do
# ...
end
end
describe "and if categories are not valid" do
# ...
end
describe "and if some common service params are not valid" do
# ...
end
end
describe "if no user is logged in, but params are valid" do
before(:each) do
save_categories_1_and_2
end
it "doesn't create a new service" do
# ...
end
it "doesn't create associations with categories" do
# ...
end
end
describe "if logged user cannot be an owner, but params are valid" do
before(:each) do
save_categories_1_and_2
end
it "doesn't create a new service" do
# ...
end
it "doesn't create associations with categories" do
# ...
end
end
end
非常感谢@midlins 和@Taryn East 为我指明了正确的轨道。 @Taryn East - 你建议的调整也适用于那里描述的情况,但在我的应用程序中我还有更高级的情况,这还不够。我觉得这里介绍的方案比较通用
您可以将您的规范设为 DRY,如下所示:
1) 使用let
而不是定义方法。
2) 安排您的 context
块,以便轻松容纳更多案例。
describe 'POST create' do
let!(:service_attributes_with_categories_1_and_2) {
FactoryBot.attributes_for :service_with_categories_1_and_2
}
let!(:category_1) { FactoryBot.build :category, {id: 1} }
let!(:category_2) { FactoryBot.build :category, {id: 2} }
let(:save_categories_1_and_2) { category_1.save && category_2.save }
context 'when user is logged in' do
context 'when user is an owner' do
context 'when params are valid' do
before do
save_categories_1_and_2
end
it 'creates a new service' do
end
it 'creates associations with categories' do
end
end
context 'when categories are not valid' do
end
context 'when some common service params are not valid' do
end
end
context 'when user is not an owner' do
context 'when params are valid' do
before do
save_categories_1_and_2
end
it "doesn't create a new service" do
end
it "doesn't create associations with categories" do
end
end
end
end
context 'when no user is logged in' do
context 'when params are valid' do
before do
save_categories_1_and_2
end
it "doesn't create a new service" do
end
it "doesn't create associations with categories" do
end
end
end
end
我如何在我的 Rails 应用程序中使用 RSpec:
这样的测试块describe "POST create" do
describe "if we have a logged in user and he can be an owner" do
describe "and if params are valid" do
let!(:service_attributes_with_categories_1_and_2) {
FactoryBot.attributes_for :service_with_categories_1_and_2
}
let!(:category_1) { FactoryBot.create :category, {id: 1} }
let!(:category_2) { FactoryBot.create :category, {id: 2} }
it "creates a new service" do
# ...
end
it "creates associations with categories" do
# ...
end
end
describe "and if categories are not valid" do
# ...
end
describe "and if some common service params are not valid" do
# ...
end
end
describe "if no user is logged in, but params are valid" do
let!(:service_attributes_with_categories_1_and_2) {
FactoryBot.attributes_for :service_with_categories_1_and_2
}
let!(:category_1) { FactoryBot.create :category, {id: 1} }
let!(:category_2) { FactoryBot.create :category, {id: 2} }
it "doesn't create a new service" do
# ...
end
it "doesn't create associations with categories" do
# ...
end
end
describe "if logged user cannot be an owner, but params are valid" do
let!(:service_attributes_with_categories_1_and_2) {
FactoryBot.attributes_for :service_with_categories_1_and_2
}
let!(:category_1) { FactoryBot.create :category, {id: 1} }
let!(:category_2) { FactoryBot.create :category, {id: 2} }
it "doesn't create a new service" do
# ...
end
it "doesn't create associations with categories" do
# ...
end
end
end
如我们所见,我有很多冗余的 let!
方法调用,但我不知道如何让它变干。我不能只定义普通方法,因为那样的话,变量将只在这个方法的范围内可用。我也不能让我的类别在一般范围内创建,因为在两种情况下,由于测试性质,它们不应该被创建。那么,我应该如何在技术上做到这一点?
最后我决定将 FactoryBot.create
函数拆分为两个步骤:FactoryBot.build
和 .save
函数 运行 在获得的对象上。它允许我将我的 let!
调用移动到主范围,并定义方法,它在我需要的情况下准确地保存我构建的对象。我的 DRY 代码现在看起来像这样:
describe "POST create" do
let!(:service_attributes_with_categories_1_and_2) {
FactoryBot.attributes_for :service_with_categories_1_and_2
}
let!(:category_1) { FactoryBot.build :category, {id: 1} }
let!(:category_2) { FactoryBot.build :category, {id: 2} }
def save_categories_1_and_2
category_1.save
category_2.save
end
describe "if we have a logged in user and he can be an owner" do
describe "and if params are valid" do
before(:each) do
save_categories_1_and_2
end
it "creates a new service" do
# ...
end
it "creates associations with categories" do
# ...
end
end
describe "and if categories are not valid" do
# ...
end
describe "and if some common service params are not valid" do
# ...
end
end
describe "if no user is logged in, but params are valid" do
before(:each) do
save_categories_1_and_2
end
it "doesn't create a new service" do
# ...
end
it "doesn't create associations with categories" do
# ...
end
end
describe "if logged user cannot be an owner, but params are valid" do
before(:each) do
save_categories_1_and_2
end
it "doesn't create a new service" do
# ...
end
it "doesn't create associations with categories" do
# ...
end
end
end
非常感谢@midlins 和@Taryn East 为我指明了正确的轨道。 @Taryn East - 你建议的调整也适用于那里描述的情况,但在我的应用程序中我还有更高级的情况,这还不够。我觉得这里介绍的方案比较通用
您可以将您的规范设为 DRY,如下所示:
1) 使用let
而不是定义方法。
2) 安排您的 context
块,以便轻松容纳更多案例。
describe 'POST create' do
let!(:service_attributes_with_categories_1_and_2) {
FactoryBot.attributes_for :service_with_categories_1_and_2
}
let!(:category_1) { FactoryBot.build :category, {id: 1} }
let!(:category_2) { FactoryBot.build :category, {id: 2} }
let(:save_categories_1_and_2) { category_1.save && category_2.save }
context 'when user is logged in' do
context 'when user is an owner' do
context 'when params are valid' do
before do
save_categories_1_and_2
end
it 'creates a new service' do
end
it 'creates associations with categories' do
end
end
context 'when categories are not valid' do
end
context 'when some common service params are not valid' do
end
end
context 'when user is not an owner' do
context 'when params are valid' do
before do
save_categories_1_and_2
end
it "doesn't create a new service" do
end
it "doesn't create associations with categories" do
end
end
end
end
context 'when no user is logged in' do
context 'when params are valid' do
before do
save_categories_1_and_2
end
it "doesn't create a new service" do
end
it "doesn't create associations with categories" do
end
end
end
end