A Guide To RSpec Built-in Matchers Part 2

Predicate, All, & Be Matchers

Click here for Part 1

Click here for Part 3

In this series of blogs, we will be going through some of RSpec’s most useful built-in matchers for writing assertions in examples. RSpec is known for its beautiful english-like syntax and matchers are no exception. Whether you’re completely new to testing in Ruby or a unit testing veteran, this guide aims to be a comprehensive introduction/review on some of the most common built-in matchers available to the RSpec library.

Continuing on from Part 1, we will be focusing on three built-in matchers that are based around boolean values and concepts. I particularly enjoy using this week’s matchers because, as you’ll soon see with predicate matchers, they are closely related to their vanilla Ruby counterparts and comprise some of the most useful built-in matchers featured in RSpec.

Predicate Matchers

In Ruby, a predicate method is defined with a at the end of the method name and returns a boolean value based on the argument provided to it. Predicate methods do not need to end with a question mark, but it is considered best-practice to do so. Some of the most common predicate methods include , , , and .

In RSpec, each predicate method has an accompanying matcher that can be used for testing purposes. Calling these predicate matchers within an assertion is very straightforward: simply remove the at the end and prepend the phrase to the start of the method name. For example:

even? -> be_even
odd? -> be_odd
zero? -> be_zero

Couldn’t be simpler, right? Naturally, every predicate method that Ruby offers can be converted to a predicate matcher in this fashion. They can also be used in conjunction with either or to further alter the boolean values being returned.

Using the four methods referenced above, let’s write some examples and assertions implementing predicate matchers that expect true or false values to be returned:

Any predicate method in Ruby can be converted and used as a matcher in an RSpec assertion.

Since all predicate matchers begin with the keyword, it can be difficult and confusing when differentiating between predicate matchers and other matchers such as comparisons and, as we will later see, truthy/falsey/nil matchers. However, these naming conventions for different kinds of matchers are insignificant.

The purpose of grouping these matchers within defined names is simply to organize the contents of this guide. As long as you clearly understand what your assertions are checking for, and what values they should return, you needn’t worry about issues such as whether your assertion uses a predicate or comparison matcher. If all else fails, the Ruby and RSpec docs never fail to procure additional information and details related to these groups of matchers.

The all Matcher

The matcher in RSpec is specifically designed to test collections/reference types in Ruby and be used together with other matchers. When passed to an assertion after the or method, it checks every element within a collection and returns false unless every single element meets the expectation. Again, it should be emphasized that is meant to be used together with other RSpec methods such as comparison or predicate matchers.

Passing in another method to the matcher is just like any other argument in Ruby: you can do so inside of parenthesis or separate it with a space after

expect([1, 3, 5]).to all(be_odd)
expect([2, 4, 6]).to all be_even

Let’s try writing some examples to test an array of numbers. We want to check whether all the values inside our array are even and whether each value is within a certain range.

Other matchers can be used in-tandem with the all matcher, as long as the subject is a collection.

Through this example group, you can hopefully see just how versatile the matcher is and how naturally it combines with predicate, comparison, or even equality matchers. The RSpec syntax is phenomenal at clearly describing what each example is checking and what each assertion should return.

RSpec’s ability to combine different keyword methods like , , and make it so that even Ruby newbies can learn almost everything they need to know about how a codebase works from the spec files. This is an extremely useful tool to add to any developer’s arsenal.

be Matchers with Truthy, Falsey, & Nil values

Inside the Ruby landscape we all know and love, all values possess an innate level of “truthiness” or “falsiness”. In other words, everything in Ruby will evaluate to be either truthy or falsey.

Although there is some consistency across most programming languages involving truthiness/falsiness, Ruby only contains two falsey values: and . Everything else, whether it is a string, integer, float, array, hash, or 0, will always evaluate to be truthy.

RSpec also allows us to test subjects using the keyword together with truthy, falsey, or nil assertions. Remember, is a special Ruby object that represents an absence of value. Therefore, anything that computes to will inherently be “falsey” AND “nil”.

In order to use matchers with truthy/falsey/nil values, simply append the appropriate word to using an underscore. As earlier stated, these methods are very similar to how other predicate matchers are used in RSpec.

expect("Daisaku Kuze").to be_truthy
expect(!1988).to be_falsey
expect(nil).to be_nil

Since any value besides and are “falsey”, these matchers can be a great way to check for the existence of certain objects or variables within your code. Lastly, let’s practice by writing out a bunch of assertions in RSpec that check for truthy/falsey values:

Notice that false & nil are considered “falsey” but only no value at all can be “nil”

There are many assertions provided in this particular Gist, so please take your time when reading exactly what each line does. The secret to mastering this week’s RSpec’s matchers is having a clear understanding of truthy and falsey values, and developing the practical skills to utilize them to maximum effect in your unit tests.

To Be Continued

We have now covered equality, comparison, predicate, and matchers in RSpec, how they are used in assertions, and how they can be combined with each other. In addition to deepening our understanding of testing in Ruby, having a good command of the matchers in this blog will help you develop ways to write a wide variety of examples in your spec files. Next week, we will touch on even more built-in matchers and take things to the next level with Ruby code blocks!

I am currently a student in the software engineering program at Flatiron school