英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论