如何在使用 rspec 测试 class 中的任何方法之前初始化一般上下文变量
How to initialize general context variables before testing any methods within a class with rspec
我是 rspec 的新手。我正在为服务 class 编写测试,我希望在任何描述块中 运行 之前初始化一堆实例。
我做了类似的事情:
RSpec.describe MyService do
before :each do
let(:product){create(:product)}
let(:article_student){ create(:article, targets: [:student], vat_type: vat_type, product: product)} #target student
let(:article_teacher){ create(:article, targets: [:teacher], vat_type: vat_type, product: product) }#target teacher
# creer des offres
let(:offer){create(:offer, target: :student, license_length: :m12)}
let(:offer_special_cyclic){create(:offer_special, cyclic_amount: true, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let(:offer_special_non_cyclic){create(:offer_special, cyclic_amount: false, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let(:order){ create(:order, establishment_account: establis
hment_account)}
end
然后我将有几个 describe 块(测试 MyService 中的不同方法,我希望在每个方法中修改之前在 :each 块中创建的变量。
例如:
describe "#create_from_order" do
subject{ licenses }
context "first time worker runs" do
order.already_went_through_license_worker = false
order.save!
LicenseService.new.create_from_order(@order.id)
let(:licenses){ License.where(order_id: @order.id)}
specify { subject.count.to eq 34 }
specify { subject.pluck(:is_from_offer_special).count(true).to eq 4}
specify { subject.pluck(:is_from_offer_special).count(false).to eq 30 }
end
end
然而,当我尝试 运行 我的测试时,我发现 context
块中的 order
未定义...
undefined local variable or method `order' for #<Class:0x007fc689ddfdb8>
我意识到我之前:每个代码都没有输入。实现此目的的好方法是在测试 class.
中的任何方法之前初始化一堆实例变量一般上下文
试试这个方法
RSpec.describe MyService do
describe "#create_from_order" do
let(:product){create(:product)}
let(:article_student){ create(:article, targets: [:student], vat_type: vat_type, product: product)} #target student
let(:article_teacher){ create(:article, targets: [:teacher], vat_type: vat_type, product: product) }#target teacher
# creer des offres
let(:offer){create(:offer, target: :student, license_length: :m12)}
let(:offer_special_cyclic){create(:offer_special, cyclic_amount: true, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let(:offer_special_non_cyclic){create(:offer_special, cyclic_amount: false, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let(:order){ create(:order, establishment_account: establishment_account)}
context "first time worker runs" do
order.already_went_through_license_worker = false
order.save!
LicenseService.new.create_from_order(@order.id)
let(:licenses){ License.where(order_id: @order.id)}
specify { subject.count.to eq 34 }
specify { subject.pluck(:is_from_offer_special).count(true).to eq 4}
specify { subject.pluck(:is_from_offer_special).count(false).to eq 30 }
end
end
end
另外 let
方法 运行 如果只调用对象。如果你想让它无论如何都是运行,你应该使用let!
方法。
希望对您有所帮助
首先,将您的 let
语句移出 before
块。 let
是延迟计算的,这意味着您定义的块 (let(:foo) { block }
) 仅在调用 foo
时执行。但是通过将语句包装在 before
块中,您实际上并没有调用它们,因此什么也不会发生。
要在每个测试之前执行语句,请使用 let!
。这不是惰性求值,并且会在您定义语句后立即执行,这正是您在本例中想要的。
RSpec.describe MyService do
let!(:product){create(:product)}
let!(:article_student){ create(:article, targets: [:student], vat_type: vat_type, product: product)} #target student
let!(:article_teacher){ create(:article, targets: [:teacher], vat_type: vat_type, product: product) } #target teacher
# creer des offres
let!(:offer){create(:offer, target: :student, license_length: :m12)}
let!(:offer_special_cyclic){create(:offer_special, cyclic_amount: true, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let!(:offer_special_non_cyclic){create(:offer_special, cyclic_amount: false, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let!(:order){ create(:order, establishment_account: establishment_account)}
end
现在,要修改对象,请在上下文中使用 before
块。并确保你没有混合 order
和 @order
.
context "first time worker runs" do
before do
order.already_went_through_license_worker = false
order.save!
LicenseService.new.create_from_order(order.id)
end
let(:licenses){ License.where(order_id: order.id)}
specify { subject.count.to eq 34 }
specify { subject.pluck(:is_from_offer_special).count(true).to eq 4}
specify { subject.pluck(:is_from_offer_special).count(false).to eq 30 }
end
这应该可以解决您的问题。
我是 rspec 的新手。我正在为服务 class 编写测试,我希望在任何描述块中 运行 之前初始化一堆实例。 我做了类似的事情:
RSpec.describe MyService do
before :each do
let(:product){create(:product)}
let(:article_student){ create(:article, targets: [:student], vat_type: vat_type, product: product)} #target student
let(:article_teacher){ create(:article, targets: [:teacher], vat_type: vat_type, product: product) }#target teacher
# creer des offres
let(:offer){create(:offer, target: :student, license_length: :m12)}
let(:offer_special_cyclic){create(:offer_special, cyclic_amount: true, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let(:offer_special_non_cyclic){create(:offer_special, cyclic_amount: false, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let(:order){ create(:order, establishment_account: establis
hment_account)}
end
然后我将有几个 describe 块(测试 MyService 中的不同方法,我希望在每个方法中修改之前在 :each 块中创建的变量。 例如:
describe "#create_from_order" do
subject{ licenses }
context "first time worker runs" do
order.already_went_through_license_worker = false
order.save!
LicenseService.new.create_from_order(@order.id)
let(:licenses){ License.where(order_id: @order.id)}
specify { subject.count.to eq 34 }
specify { subject.pluck(:is_from_offer_special).count(true).to eq 4}
specify { subject.pluck(:is_from_offer_special).count(false).to eq 30 }
end
end
然而,当我尝试 运行 我的测试时,我发现 context
块中的 order
未定义...
undefined local variable or method `order' for #<Class:0x007fc689ddfdb8>
我意识到我之前:每个代码都没有输入。实现此目的的好方法是在测试 class.
中的任何方法之前初始化一堆实例变量一般上下文试试这个方法
RSpec.describe MyService do
describe "#create_from_order" do
let(:product){create(:product)}
let(:article_student){ create(:article, targets: [:student], vat_type: vat_type, product: product)} #target student
let(:article_teacher){ create(:article, targets: [:teacher], vat_type: vat_type, product: product) }#target teacher
# creer des offres
let(:offer){create(:offer, target: :student, license_length: :m12)}
let(:offer_special_cyclic){create(:offer_special, cyclic_amount: true, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let(:offer_special_non_cyclic){create(:offer_special, cyclic_amount: false, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let(:order){ create(:order, establishment_account: establishment_account)}
context "first time worker runs" do
order.already_went_through_license_worker = false
order.save!
LicenseService.new.create_from_order(@order.id)
let(:licenses){ License.where(order_id: @order.id)}
specify { subject.count.to eq 34 }
specify { subject.pluck(:is_from_offer_special).count(true).to eq 4}
specify { subject.pluck(:is_from_offer_special).count(false).to eq 30 }
end
end
end
另外 let
方法 运行 如果只调用对象。如果你想让它无论如何都是运行,你应该使用let!
方法。
希望对您有所帮助
首先,将您的 let
语句移出 before
块。 let
是延迟计算的,这意味着您定义的块 (let(:foo) { block }
) 仅在调用 foo
时执行。但是通过将语句包装在 before
块中,您实际上并没有调用它们,因此什么也不会发生。
要在每个测试之前执行语句,请使用 let!
。这不是惰性求值,并且会在您定义语句后立即执行,这正是您在本例中想要的。
RSpec.describe MyService do
let!(:product){create(:product)}
let!(:article_student){ create(:article, targets: [:student], vat_type: vat_type, product: product)} #target student
let!(:article_teacher){ create(:article, targets: [:teacher], vat_type: vat_type, product: product) } #target teacher
# creer des offres
let!(:offer){create(:offer, target: :student, license_length: :m12)}
let!(:offer_special_cyclic){create(:offer_special, cyclic_amount: true, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let!(:offer_special_non_cyclic){create(:offer_special, cyclic_amount: false, free_article_id: article_teacher.id, minimum_amount: 10, license_length: :m12)} # free article @article_teacher
let!(:order){ create(:order, establishment_account: establishment_account)}
end
现在,要修改对象,请在上下文中使用 before
块。并确保你没有混合 order
和 @order
.
context "first time worker runs" do
before do
order.already_went_through_license_worker = false
order.save!
LicenseService.new.create_from_order(order.id)
end
let(:licenses){ License.where(order_id: order.id)}
specify { subject.count.to eq 34 }
specify { subject.pluck(:is_from_offer_special).count(true).to eq 4}
specify { subject.pluck(:is_from_offer_special).count(false).to eq 30 }
end
这应该可以解决您的问题。