RSpec's #to Method Takes the 2nd Argument As Its failing-message
Posted on by Gentaro "hibariya" Terada
Today I learned that RSpec's #to
method takes the 2nd argument as its custom failing-message.
expect(actual_value).to eq(expected_value), message
Let's say we are going to test a JSON object. The following example expects a part of the JSON object response_json['eye_colour']
to be "blue"
.
require 'net/https'
require 'uri'
require 'json'
RSpec.describe do
example do
response = Net::HTTP.get_response(URI('https://swapi.dev/api/people/1/'))
response_json = JSON.parse(response.body)
expect(response_json['eye_colour']).to eq('blue')
end
end
Unfortunately, this test fails and displays messages like this:
Failures:
1) is expected to eq "blue"
Failure/Error: expect(response_json['eye_colour']).to eq('blue')
expected: "blue"
got: nil
(compared using ==)
From this output, we could guess either response_json['eye_colour']
is set to nil
or the key eye_colour
is not defined. However, there is no more information here. To find out the cause of the error, an additional print-debug would be needed.
@@ -7,6 +7,7 @@ RSpec.describe do
response = Net::HTTP.get_response(URI('https://swapi.dev/api/people/1/'))
response_json = JSON.parse(response.body)
+ p response_json
expect(response_json['eye_colour']).to eq('blue')
end
end
It's no big deal. We could do this when we need additional information. But there is another option. RSpec::Expectations::ExpectationTarget#to
takes 2nd argument. When the expectation failed, RSpec shows it as a custom failing-message.
@@ -7,6 +7,6 @@ RSpec.describe do
response = Net::HTTP.get_response(URI('https://swapi.dev/api/people/1/'))
response_json = JSON.parse(response.body)
- expect(response_json['eye_colour']).to eq('blue')
+ expect(response_json['eye_colour']).to eq('blue'), response_json.inspect
end
end
By this change, RSpec will display response_json
as the custom failing-message, and then we could notice that eye_colour
should be eye_color
.
Failures:
1) is expected to eq "blue"
Failure/Error: expect(response_json['eye_colour']).to eq('blue'), response_json.inspect
{"name"=>"Luke Skywalker", "height"=>"172", "mass"=>"77", "hair_color"=>"blond", "skin_color"=>"fair",
"eye_color"=>"blue", "birth_year"=>"19BBY", ...}
As you can see, there are no big differences between the temporally print-debug and the custom failing-message for this example. That said, what if it shows up from time to time, what if we could reproduce it only on CI. In these cases, this kind of additional information would give you lots of insights quickly. Instead of putting print-debug code over and over again, we could always pass a custom failing-message for expectations that need more information to fix.
See Also
- https://relishapp.com/rspec/rspec-expectations/v/3-10/docs/customized-message
- https://www.rubydoc.info/gems/rspec-expectations/RSpec/Expectations/ExpectationTarget/InstanceMethods#to-instance_method
- https://github.com/stripe-samples/checkout-single-subscription/commit/5d7db0e61e849ba7e103c83cfca2c9cd269f244a