ruby-on-rails - 如何在使用 rspec 测试类中的任何方法之前初始化通用上下文变量
问题描述
我是 rspec 的新手。我正在为服务类编写测试,并且我希望在运行任何描述块之前初始化一堆实例。我做类似的事情:
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
然后我将有几个描述块(测试 MyService 中的不同方法,我希望在每个方法中修改我之前创建的变量:每个块。例如:
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
但是,当我尝试运行测试时,我发现order
我的context
块内部没有定义......
undefined local variable or method `order' for #<Class:0x007fc689ddfdb8>
我意识到我之前的:从未输入过每个代码。实现这一点的好方法是什么,那就是在测试类中的任何方法之前初始化一堆实例变量一般上下文。
解决方案
首先,将您的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
那应该可以解决您的问题。
推荐阅读
- spring-boot - 为什么 isEmpty() 不检查 null?
- sql-server - 使用 mssql 模块的 node.js 程序 - 连接到 SQL Server 数据库失败
- linux-kernel - CentOS 7 - 在 nvme 设备上从 3.10 内核更新到 5.x 后无法启动
- r - 关于所有列,如何对整个数据框进行排序
- r - 根据多个标准对ggplot中的离散x轴进行排序
- typescript - 如何复制两个接口之间的相似性
- rust - 什么时候可以安全地将引用的生命周期延长到 Arenas?
- c# - 不知道如何在 C# 中使用这个 API
- vb.net - 思科 AnyConnect 的 AddHandler
- ruby-on-rails - 从 shopify_token 和 shopify_domain 开始新的 shopify 会话?