# Custom RSpec Matchers for arrays

More than once, I’ve had to check an array for it’s order in RSpec. Usually, I just sort the array, and compare it to itself. The spec might look something like

describe MyObject
describe "scope #ordered" do
it "returns results in most recent order"
expect(MyObject.ordered.all.sort(&:attr_to_order_by)).to eql my_objects
end
end
end


This may seem a bit opaque (as a reader) – how does the sorting relate to the test? Also, if you looking at timestamps (like sort by created_at), and you’re using fixtures or FactoryGirl.create, you may end up with duplicate timestamps. Suddenly your sort will be ill defined because the secondary sort key is undefined. A better method would be to check that the :created_at time is monotonically decreasing.

An array x is monotonically decreasing if and only if:
$x_i \geq x_j \forall i < j$

For these kinds of cases, I decided to write a some RSpec matchers. Following the RSpec Wiki docs here, it was a snap. I wrote matchers for monotonically increasing/decreasing and strictly increasing/decreasing tests.

The following four matchers (available from this gist (included below)) give you

   be_monotonically_increasing
be_strictly_increasing
be_monotonically_decreasing
be_strictly_decreasing


So now I can rewrite my spec

describe MyObject
describe "scope #ordered" do
it "returns results in most recent order"
# the most recent object should have the largest created_by timestamp
expect(MyObject.ordered.map(&:created_by)).to be_monotonically_decreasing
end
end
end


These matchers follow the definitions from NIST for monotonically/strictly increasing/decreasing (see links below). The short story is:

Monotonically Increasing means:
$x_i \leq x_j \forall < j$

Strictly Increasing means:
$x_i < x_j \forall i < j$

Monotonically Decreasing means:
$x_i \geq x_j \forall i < j$

Strictly Decreasing means:
$x_i > x_j \forall i < j$

To use these, put the gist (below) custom_array_matchers.rb file in your spec/support directory and you’re off to the races. You can start using those matchers in your specs. The gist also includes specs that test the matchers. If the matcher names aren’t clear, check out the specs and hopefully that’ll reveal what they do. The algorithm itself is pretty simple – take a derivative of the array values and make sure that it’s always positive (or negative) in slope for increasing (or decreasing) checks.

The code is built for RSpec 2.something (at a minimum). They also assume your sort attribute is an number. I haven’t tried it with strings, but I think it wouldn’t take much to modify things to handle more general cases. Perhaps I’ll run into that problem and have an update. Until then, they are what they are.

## 5 thoughts on “Custom RSpec Matchers for arrays”

1. Glad it was helpful. A delightful surprise that 2 years later they’re still viable. I know I’m still using them in various projects.

1. akestner says:

(Still) super helpful, thanks a bunch!

2. Dennis says:

You can use RSpec’s equality matcher when order in arrays matter.

“
Failure/Error: expect([1, 2, 3]).to eq([1, 3, 2])

expected: [1, 3, 2]
got: [1, 2, 3]

(compared using ==)
“

The eql matcher also works.

3. That’s true. If the array is big, it can be tedious to write out all the expected values, so if I expect the order to be descending or ascending (like things are ordered by timestamps or something), these helpers can be handy.