【问题标题】:RSpec matcher that checks collection to include item that satisfies lambdaRSpec 匹配器检查集合以包含满足 lambda 的项目
【发布时间】:2015-05-27 08:07:05
【问题描述】:

对于如何编写 RSpec 3.2.x 规范来检查列表是否包含至少一个满足条件的项目,我有点不知所措。

这是一个例子:

model = Invoice.new
model.name = 'test'
changes = model.changes
expect(changes).to include { |x| x.key == 'name' && x.value == 'test' }

更改列表中也会有其他(自动)更改,所以我不想验证是否只有一个特定更改,我也不想依赖订购expect(changes.first)...,所以我基本上需要一个指定列表中至少一项更改满足条件的方法。

我可以这样做:

result = changes.any? { |x| x.key == 'name' .. }
expect(result).to eq(true)

但是 rspec 失败不会给我任何有意义的输出,所以我认为必须有一个内置的方法来匹配它。

也欢迎任何其他关于如何构建测试的建议。

编辑:要清楚 - 更改是 ChangeObject 的列表,所以我需要访问他们的 .key.value 方法

【问题讨论】:

    标签: ruby rspec rspec-rails rspec3


    【解决方案1】:

    在 RSpec 3 中,matchers are fully composable,这意味着您可以将任何实现 Ruby 的=== 协议(包括匹配器!)的对象传递给include,它会正常工作。 Ruby 1.9 中的 Lambda 实现了=== 协议,这意味着您可以这样做:

    expect(changes).to include(lambda { |x| x.key == 'name' && value == 'test' })
    

    也就是说,这不会给你一个很好的失败消息(因为 RSpec 无法生成 lambda 的描述)。我不确定value 在您的示例中来自哪里,但如果它打算是x.value,您可以使用have_attributes(或an_object_having_attributes 以获得更好的可读性)匹配器:

    expect(changes).to include an_object_having_attributes(key: 'name', value: 'test')
    

    【讨论】:

    【解决方案2】:

    试试这个

    expect(changes).to be_any{ |x| //logic to match }
    

    【讨论】:

    • 不幸的是,这不起作用,因为它不是散列而是对象。我会澄清这个问题
    • 我也无法检查匹配对象的相等性,因为该对象是在类内部构造的,我不想破坏可见性规则。
    • 在这种情况下,"expect(changes).to be_include { |x| x.key == 'name' && value == 'test' }" 就可以了
    • be_include 引发参数错误,但您为我指明了正确的方向。 be_any { |x| .. } 为我解决了这个问题。请更新答案,以便我将其标记为已接受
    猜你喜欢
    • 2014-11-14
    • 1970-01-01
    • 2019-01-28
    • 1970-01-01
    • 2020-01-08
    • 1970-01-01
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多