问题
I am a bit at a loss as to how to write a RSpec 3.2.x spec that checks wether a list contains at least one item that satisfies a condition.
Here is an example:
model = Invoice.new
model.name = 'test'
changes = model.changes
expect(changes).to include { |x| x.key == 'name' && x.value == 'test' }
There will be other (automated) changes in the changes list too so I don't want to verify that there is only one specific change and I also don't want to rely on ordering expect(changes.first)...
so I basically need a way to specify that at least one change in the list satisfies the condition.
I could do something like this:
result = changes.any? { |x| x.key == 'name' .. }
expect(result).to eq(true)
But then the rspec failure would not give me any meaningful output so I thought there must be a built-in way to match this.
Any other suggestions on how to structure the test are also welcome.
Edit: To be clear - the changes are a list of ChangeObject so I need to access their .key
and .value
method
回答1:
In RSpec 3, matchers are fully composable, which means you can pass any object which implements Ruby's ===
protocol (including a matcher!) to include
and it will work properly. Lambdas in Ruby 1.9 implement the ===
protocol, which means you can do this:
expect(changes).to include(lambda { |x| x.key == 'name' && value == 'test' })
That said, that's not going to give you a great failure message (since RSpec has no way to generate a description of the lambda). I'm not sure where value
comes from in your example, but if it is intended to be x.value
, you could use the have_attributes
(or an_object_having_attributes
for better readability) matcher:
expect(changes).to include an_object_having_attributes(key: 'name', value: 'test')
回答2:
Try this
expect(changes).to be_any{ |x| //logic to match }
来源:https://stackoverflow.com/questions/30476624/rspec-matcher-that-checks-collection-to-include-item-that-satisfies-lambda