Skip to content

Instantly share code, notes, and snippets.

@ianks

ianks/blog.md Secret

Created June 17, 2017 00:01
Show Gist options
  • Save ianks/5379d90a79440569aca7adbef05872a4 to your computer and use it in GitHub Desktop.
Save ianks/5379d90a79440569aca7adbef05872a4 to your computer and use it in GitHub Desktop.

A quick trick for creating fluent RSpec matchers

RSpec matchers are a powerful tool. They allow you describe what your intentions are in a concise and accurate way.

However, like anything meant to be interpreted by a machine, they can become verbose.

Imagine we have a Post class, which has a list of comments stored managed by some external service that we access over HTTPs.

https://gist.github.com/34f72da118bf565aef43b2e56ec40236

We want to test that we call the API with the correct parameters. It's a simple proposition, but the expectation can become a little unwieldy and repetitive:

https://gist.github.com/2a1183e0c1127d3c4640088983c0565f

Not terrible, but certainly a bit verbose and repetitive. We can do better.

In RSpec, the argument received by .to is called a "matcher." Matchers define the expectations for the behavior of the "subject" you are testing. Although "matchers" give you a nice syntax for describing what is being tested, they can quickly become procedural. In our example, a significant portion of the matcher is boilerplate and/or implementation details.

Luckily, RSpec gives you a way to define Custom Matchers! I know, very exciting!

https://gist.github.com/ff242b3d3cf8ad6069a165c2e4ead983

However, in my experience, people do not begin creating Custom Matchers until expectations get extremely unwieldy. It's not because I do not like them, it is because I can never remember the syntax.

Luckily, matchers are easy to create. In fact, you create them for every spec. Since matchers are just encapsulated objects, you can name them!

So these days instead of writing a Custom Matcher, I define a plain-old Ruby Method (PORM?) which returns a matcher. If the matcher becomes useful enough that is justifies it's own Custom Matcher, I will extract it then.

Now, our new spec now becomes:

https://gist.github.com/165b998ae3a50a2eaae8e9267208817e

Much simpler, eh?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment