2010-11-10 63 views
12

我正在用rspec测试我的模型的验证,并且期待一条错误消息。但是,邮件的确切文本可能会发生变化,所以我想要更宽容一些,只检查部分邮件。RSpec:通过正则表达式匹配字符串数组

由于规格::匹配器::包括方法仅适用于字符串和收藏,我目前使用这个结构:

@user.errors[:password].any?{|m|m.match(/is too short/)}.should be_true 

这工作,但似乎有点麻烦我。是否有更好的(即更快或更像ruby)的方式来检查数组是否包含正则表达式的字符串,或者可能是一个rspec匹配器来做这件事?

+2

做一个自定义的匹配器 – shingara 2010-11-10 15:54:55

回答

16

我建议做

@user.errors[:password].to_s.should =~ /is too short/ 

很简单,因为它会给你一个更失败时有用的错误。如果你使用be_any那么你得到这样的消息......

Failure/Error: @user.errors[:password].should be_any{ |m| m =~ /is too short/} 
    expected any? to return true, got false 

但是,如果您使用to_s方法,那么你会得到这样的事情:

Failure/Error: @user.errors[:password].to_s.should =~ /is too short/ 
    expected: /is to short/ 
     got: "[]" (using =~) 
    Diff: 
    @@ -1,2 +1,2 @@ 
    -/is too short/ 
    +"[]" 

所以你可以看到的原因因为失败并且不需要花太多的精力来弄清楚为什么失败。

+0

这是我一直使用的版本,效果很好。我同意,当你使用'be_any' – nzifnab 2012-09-07 22:07:38

8

我不认为它使的性能差异,但一个更RSpec的类似解决方案是

@user.errors[:password].should be_any { |m| m =~ /is too short/ } 
+0

更好,谢谢。现在,如果我只能找到be_any的文档... – Thilo 2010-11-10 17:30:49

+0

至于文档,请查看http://rubydoc.info/gems/rspec-expectations/2.0.1/frames。 'be_any'是从'Enumerable'的'any?'谓词中动态生成的。 – zetetic 2010-11-10 19:09:38

+0

我可以看到'any?'如何转换成'be_any',但听起来不像英语好。 – 2010-11-10 22:49:10

9

你可以把投机/支持/ custom_matchers.rb下面的代码

RSpec::Matchers.define :include_regex do |regex| 
    match do |actual| 
    actual.find { |str| str =~ regex } 
    end 
end 

现在你可以像这样使用它:

@user.errors.should include_regex(/is_too_short/) 

,并确保你有投机/ spec_helper.rb

Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} 
+0

时,发现模糊的错误信息出了什么问题是很困难的。谢谢! – 2013-09-12 16:47:14

0

只是另一种选择是这样的

@user.errors[:password].grep /is too short/ 
2

我的这个解决方案是类似于@ muirbot的。我使用自定义匹配器。但是,我使用真正的include匹配器,但用自定义匹配器作为参数来增加它。在套件运行之前将其加载到某个位置(例如,在spec/support/matchers.rb中,依次由spec/spec_helper加载)。RB):

RSpec::Matchers.define(:a_string_matching) do |expected| 
    match do |actual| 
    actual =~ expected 
    end 
end 

那么你的期望可以这样写:

expect(@user.errors[:password]).to include(a_string_matching(/is too short/)) 
+0

'a_string_matching' [已经是RSpec的一部分](https://github.com/rspec/rspec-expectations/blob/3b8d6a55d75d02039f3b95555690d9f987da1f82/lib/rspec/matchers.rb#L677),所以不需要定义它。从RSpec 3.0支持编写匹配器 – 2014-09-16 09:17:05

5

使用RSpec 3 expect syntaxmatchers composing

匹配所有:

expect(@user.errors[:password]).to all(match /some message/) 

要匹配任意:

expect(@user.errors[:password]).to include(match /some message/) 
expect(@user.errors[:password]).to include a_string_matching /some message/ 
+0

这并不完全正确。我希望**至少有一个**密码错误匹配字符串,但不一定**全部**。 – Thilo 2014-09-15 18:21:50

+0

我的不好。然后'expect(@ user.errors [:password])。包含(match/some message /)'或者甚至更好'expect(@ user.errors [:password])来包含a_string_matching/some message / – 2014-09-16 09:02:45