我今天在定义我解决的自定义 RSpec 匹配器时遇到了一个问题,但实际上看不出任何一种方法有效而另一种方法无效的原因,这是代码:
方法 1——if + else:
RSpec::Matchers.define :have_success_message do |message|
match do |page|
if message.nil?
page.should have_selector('div.alert.alert-success')
else
page.should have_selector('div.alert.alert-success', text: message)
end
end
end
方法 2 -- if 后跟 unless
RSpec::Matchers.define :have_success_message do |message|
match do |page|
page.should have_selector('div.alert.alert-success') if message.nil?
page.should have_selector('div.alert.alert-success', text: message) unless message.nil?
end
end
我认为第一种方法更好,因为它只检查一次条件,但无论如何,结果应该是一样的,对吧?
好吧,事实证明第一种方法的测试通过了,而第二种方法的测试没有通过。我完全不知道为什么会这样,如果有人能对此有所了解,我会很高兴。
编辑:
忘记添加实际测试(使用方法 2):
存在以下 HTML 标记:
<div class="alert alert-success">Profile updated</div>
我运行 4 个独立的测试:
it { should have_success_message } # fails
it { should have_success_message('Profile updated') } # passes
it { should have_selector('div.alert.alert-success') } # passes
it { should have_selector('div.alert.alert-success', text: "Profile updated") } # passes
失败的消息如下:
1) User pages edit with valid information
Failure/Error: it { should have_success_message }
expected #<Capybara::Session> to have success message
# ./spec/requests/user_pages_spec.rb:80:in `block (5 levels) in <top (required)>'
当 HTML 标签不存在时,所有 4 个测试都会失败。
编辑 2:
我尝试了另一种方法来验证控制流是否正确:
方法 3:
if message.nil?
puts "In if, message is: #{message.inspect}"
page.should(have_selector('div.alert.alert-success'))
end
unless message.nil?
puts "In unless, message is: #{message.inspect}"
page.should(have_selector('div.alert.alert-success', text: message))
end
使用这种方法的行为与方法 2 相同 - 第一个测试失败,然后第三次通过。
输出如下:
In if, message is: nil
In unless, message is: "Profile updated"
所以控制流看起来没问题,但是
page.should(have_selector('div.alert.alert-success'))
失败,即使它通过了匹配器之外。这真是一个谜。
最终编辑:
只是为了回应已批准的答案 - 当我这样切换代码时:
page.should have_selector('div.alert.alert-success', text: message) unless message.nil?
page.should have_selector('div.alert.alert-success') if message.nil?
测试看起来像这样:
it { should have_success_message } # passes
it { should have_success_message('Profile updated') } # fails
it { should have_selector('div.alert.alert-success') } # passes
it { should have_selector('div.alert.alert-success', text: "Profile updated") } # passes
所以我认为确实最后一行,当它不是真的时,被评估为零,这导致了整个困惑。无论如何,第一种方法更好,但我很高兴我已经解决了这个问题:)
最佳答案
这是 RSpec 的正确行为,即使它看起来出乎意料。
考虑这段代码:
x = nil
"foo" if x.nil?
"bar" unless x.nil?
#=>
"foo"
nil
当条件为假时,...unless
语句返回 nil
。
在您的自定义匹配器中,当您的消息为 nil 时,...unless
语句返回 nil。
那是你的匹配 block 中的最后一行,所以你的匹配 block 返回 nil。
然后 RSpec 看到您的匹配 block 返回 nil,RSpec 认为这与 false 相同,因此 RSpec 报告您的自定义匹配器失败。
关于ruby - if + else 和 if -> unless 不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13663163/