用于检查集合以包含满足 lambda 的项目的 RSpec 匹配器

Tig*_*ine 2 ruby rspec rspec-rails rspec3

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

下面是一个例子:

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

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

我可以做这样的事情:

result = changes.any? { |x| x.key == 'name' .. }
expect(result).to eq(true)
Run Code Online (Sandbox Code Playgroud)

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

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

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

Myr*_*ton 5

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

expect(changes).to include(lambda { |x| x.key == 'name' && value == 'test' })
Run Code Online (Sandbox Code Playgroud)

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

expect(changes).to include an_object_having_attributes(key: 'name', value: 'test')
Run Code Online (Sandbox Code Playgroud)