如何改写DRY的RSpec用例以消除隐式块预期弃用警告
解决RSpec隐式块弃用警告并保持代码DRY
问题背景
在将项目从Rails 5迁移至Rails 6(当前环境:Rails 6.0.6.1、RSpec 3.12.0、rspec-rails 5.1.2)时,编写的RSpec代码触发了隐式块预期语法已弃用,应向expect传递块而非参数的警告。
原代码如下:
describe "Create with a classification class added" do before do @lambda_block = lambda { click_button I18n.t(:button_save) expect(page).to have_text(I18n.t :'flash.classification_scheme.create_success') } end describe "Save should create a ClassificationScheme and a ClassificationSchemesClass" do subject { @lambda_block } it { is_expected.to change(ClassificationScheme, :count).by(1) } it { is_expected.to change(ClassificationSchemesClass, :count).by(1) } end end
修改为无警告版本后,代码出现重复,违反DRY原则:
describe "Create with a classification class added" do it "Save should create a ClassificationScheme" do expect{ click_button I18n.t(:button_save) expect(page).to have_text(I18n.t :'flash.classification_scheme.create_success') }.to change{ClassificationScheme.count}.by(1) end it "Save should create a ClassificationSchemesClass" do expect{ click_button I18n.t(:button_save) expect(page).to have_text(I18n.t :'flash.classification_scheme.create_success') }.to change{ClassificationSchemesClass.count}.by(1) end end
尝试直接传递@lambda_block时,expect{@lambda_block}不会执行lambda块,expect(@lambda_block)虽能通过测试但仍触发警告。
解决方案
要同时满足消除警告和保持DRY的需求,可以通过以下几种方式实现:
方法一:封装辅助方法
把重复的操作封装成一个方法,在expect块中调用该方法:
describe "Create with a classification class added" do def perform_save_and_verify_success click_button I18n.t(:button_save) expect(page).to have_text(I18n.t :'flash.classification_scheme.create_success') end it "creates a ClassificationScheme" do expect { perform_save_and_verify_success }.to change(ClassificationScheme, :count).by(1) end it "creates a ClassificationSchemesClass" do expect { perform_save_and_verify_success }.to change(ClassificationSchemesClass, :count).by(1) end end
方法二:调用lambda的call方法
如果坚持使用lambda,可以在expect块中调用lambda的call方法,同时改用let定义lambda(符合RSpec最佳实践):
describe "Create with a classification class added" do let(:save_and_verify) do lambda { click_button I18n.t(:button_save) expect(page).to have_text(I18n.t :'flash.classification_scheme.create_success') } end it "creates a ClassificationScheme" do expect { save_and_verify.call }.to change(ClassificationScheme, :count).by(1) end it "creates a ClassificationSchemesClass" do expect { save_and_verify.call }.to change(ClassificationSchemesClass, :count).by(1) end end
方法三:使用共享示例组
如果这类测试逻辑需要在多个地方复用,可以定义共享示例组:
RSpec.shared_examples "creates a record" do |model_class| it "creates a #{model_class.name}" do expect { click_button I18n.t(:button_save) expect(page).to have_text(I18n.t :'flash.classification_scheme.create_success') }.to change(model_class, :count).by(1) end end describe "Create with a classification class added" do include_examples "creates a record", ClassificationScheme include_examples "creates a record", ClassificationSchemesClass end
说明
RSpec 3.12+弃用了将lambda作为参数传递给expect的语法,要求必须传递可执行的块。上述方法均遵循该要求,同时避免了代码重复。
内容的提问来源于stack exchange,提问作者Tibor Nagy
相关产品推荐
相关产品推荐

