RSpec Matchers Combinators

Rspec matchers are a lot like predicates. Predicates that can talk … The good thing about predicates, as anybody who has done a bit of functional programming will tell you, is that they are easy to combine together into bigger predicates. I was really suprised to see that rspec does not come with such simple combinators as ‘and’ or ‘or’.

Here is a gist where I define simple combinators :

With this and the email_spec matchers, it is possible to write something like this to find if an email was sent by rails :

1
2
3
expect(all_emails).to have_any_that(and_(deliver_to(receiver),
                                         have_subject(subject),
                                         have_body_text(body)))

It enables expressive test code and high reusability.

Using the ‘all’ combinator it is possible to write things like that :

1
expect(sample_items_attributes).to all_ have_key(:price)

I had to prepend ‘all’ and ‘and’ with an underscore because I would otherwise get conflicts… I’m not overly satisfied with this, but it will do for the moment.

I was happily supprised by the readability of error messages when the mach fails. Rspec does a very good job about this. I think it would be possible to get even better error messages by explicity using the sub matchers messages though. If anyone is interested, help yourself !

Comments