How to change DRY a spec to avoid deprecation warning "The implicit block expectation syntax is deprecated, you should pass a block…"

huangapple go评论52阅读模式
英文:

How to change DRY a spec to avoid deprecation warning "The implicit block expectation syntax is deprecated, you should pass a block..."

问题

我明白你的问题。你想将lambda块传递给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 "should change ClassificationScheme and ClassificationSchemesClass counts" do
      expect(&@lambda_block).to change { ClassificationScheme.count }.by(1)
      expect(&@lambda_block).to change { ClassificationSchemesClass.count }.by(1)
    end
  end
end

这里使用expect(&@lambda_block)来将lambda块传递给expect,同时避免不推荐的警告。注意,我还更正了expect(page).to have_text(I18n.t :flash_classification_scheme_create_success),确保正确使用了符号而不是HTML实体。

请注意,这个解决方案需要RSpec 3.12.0或更高版本。如果你的版本不支持,请考虑升级RSpec。

英文:

I have to following rspec fragment:

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   

I get these deprecation warnings:

The implicit block expectation syntax is deprecated, you should pass a block rather than an argument to expect to use the provided block expectation matcher or the matcher must implement supports_value_expectations?. e.g expect { value }.to change ClassificationScheme.count by 1 not expect(value).to change ClassificationScheme.count by 1

The implicit block expectation syntax is deprecated, you should pass a block rather than an argument to expect to use the provided block expectation matcher or the matcher must implement supports_value_expectations?. e.g expect { value }.to change ClassificationSchemesClass.count by 1 not expect(value).to change ClassificationSchemesClass.count by 1

The deprecation warnings disappear if I change the spec as follows. expect gets a block instead of an argument, however two lines are repeated, the code is not 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

How can I pass the lambda block to expect?

If I try expect{@lambda_block}.to change... then the lambda block is not executed. If I try expect(@lambda_block).to change... then the test is passed, however I get again the deprecation warning.

The question is, how can I pass the @lambda_block to expect but avoid the deprecation warning.

I'm currently to migrate a project from rails 5 to rails 6, so the current versions:
rails 6.0.6.1
rspec 3.12.0
rspec-rails 5.1.2

答案1

得分: 2

只要让它变得清晰易懂以查看你所拥有的,我已经简化了一些内容:

subject do
  lambda { click_button I18n.t(:button_save) }     
end
it { is_expected.to change(ClassificationScheme, :count).by(1) }

当你切换到显式块时,不再需要lambda

subject do
  click_button I18n.t(:button_save)    
end
it { expect { subject }.to change(ClassificationScheme, :count).by(1) }
#           ^         ^
# 这个块已经传递给expect了,这就是你之前用lambda的地方

当你把lambda放在那个块里时,块变得嵌套,lambda永远不会被调用。你也可以通过自己调用它来解决这个问题:

subject do
  lambda { click_button I18n.t(:button_save) }     
end
it { expect { subject.call }.to change(ClassificationScheme, :count).by(1) }

当你不使用块语法{ }do end时,subject变成一个参数,这是不推荐的:

#               块必须放在这里 vvvvvv
def expect(arg = nil, keyword: :arg, &block)
# 不是在这里 ^^^  
end

你可以使用Ruby的一元运算符&来将传递的参数视为块:

subject do
  lambda { click_button I18n.t(:button_save) }     
end
it { expect(&subject).to change(ClassificationScheme, :count).by(1) }

这个比较难以快速解释:
https://medium.com/@amliving/rubys-unary-operator-a93d36d3cd8b

英文:

Just to make it nice and clear to see what you have, I've simplified this a bit:

subject do
  lambda { click_button I18n.t(:button_save) }     
end
it { is_expected.to change(ClassificationScheme, :count).by(1) }

When you change to explicit block, you no longer need lambda:

subject do
  click_button I18n.t(:button_save)    
end
it { expect { subject }.to change(ClassificationScheme, :count).by(1) }
#           ^         ^
# the block is already being passed to expect, this is where your lambda used to be

When you put lambda inside of that block, the blocks become nested and lambda never gets called. Which you can also fix by calling it yourself:

subject do
  lambda { click_button I18n.t(:button_save) }     
end
it { expect { subject.call }.to change(ClassificationScheme, :count).by(1) }

When you don't use a block syntax { } or do end, subject becomes an argument, which is deprecated:

#               block has to go here vvvvvv
def expect(arg = nil, keyword: :arg, &block)
# not here ^^^  
end

You can use ruby unary & operator to treat passed argument as a block:

subject do
  lambda { click_button I18n.t(:button_save) }     
end
it { expect(&subject).to change(ClassificationScheme, :count).by(1) }

This one is hard to explain quick:
https://medium.com/@amliving/rubys-unary-operator-a93d36d3cd8b

huangapple
  • 本文由 发表于 2023年3月8日 17:10:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75671171.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定