RSpec matcher, который проверяет коллекцию, чтобы включить элемент, который удовлетворяет лямбда

Я немного растерялся относительно того, как написать спецификацию 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 метод

2 ответа

Решение

В RSpec 3 сопоставления полностью компонуются, что означает, что вы можете передать любой объект, который реализует Ruby === протокол (включая совпадение!) include и это будет работать правильно. Лямбды в Ruby 1.9 реализуют === протокол, который означает, что вы можете сделать это:

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

Тем не менее, это не даст вам большого сообщения об ошибке (поскольку у RSpec нет способа генерировать описание лямбды). Я не уверен где value исходит из вашего примера, но если он предназначен для x.valueВы могли бы использовать have_attributes (или же an_object_having_attributes для лучшей читаемости)

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

Попробуй это

expect(changes).to be_any{ |x| //logic to match }
Другие вопросы по тегам