How to Create Matchers in RSpec
Reference: RSpec Custom Matchers
You can create custom matchers for your testing.
Let’s say that you want to test if a hash (hash_a
) contains another hash (hash_b
).
At the end of your test file, add the following matcher:
it "contains hash" do
hash_a = {bruno: "monteiro"}
hash_b = {bruno: "monteiro"}
expect(hash_a).to contains_hash(hash_b)
end
RSpec::Matchers.define :contains_hash do |hash_b|
match do |hash_a|
# >= is a ruby method to check if a hash contains another
hash_a >= hash_b
end
end
But hash_a
and hash_b
are not the greatest names for variables within your matcher.
In this case, hash_a
is going to be the expected_hash
and hash_b
is going to be
the actual_hash
...
RSpec::Matchers.define :contains_hash do |expected_hash|
match do |actual_hash|
# >= is a ruby method to check if a hash contains another
actual_hash >= expected_hash
end
end
Using diffable
Now you have a working matcher, but is the output of your matcher good? Let’s make it fail:
it "contains hash" do
hash_a = {bruno: "monteiro"}
hash_b = {bruno: "rocha"}
expect(hash_a).to contains_hash(hash_b)
end
It is easy to see why it’s failing because our hash is small, but if the hash was larger,
it would be difficult to see what is wrong with your test. So, you can use a built-in
function in Rspec: diffable
.
...
RSpec::Matchers.define :contains_hash do |expected_hash|
match do |actual_hash|
# >= is a ruby method to check if a hash contains another
actual_hash >= expected_hash
end
diffable
end
The tests are looking pretty good now.
Using chain
Now let’s say that you have a hash of hashes and you want to know if that hash contains
a certain hash. You can use the built-in RSpec function chain
:
it "contains hash" do
hash_a = {first_name: {bruno: "monteiro"}, second_name: {rocha: "lima"}}
hash_b = {bruno: "rocha"}
expect(hash_a).to contains_hash(hash_b).within(:first_name)
end
RSpec::Matchers.define :contains_hash do |expected_hash|
match do |actual_hash|
# >= is a ruby method to check if a hash contains another
actual_hash >= expected_hash
end
diffable
chain :within do |hash_value|
@hash_value = hash_value
end
end