I am using RSpec (3.x) to test an object that acts similar to a calculator. The object puts the results into a hash. But I cannot get the hash to match correctly in my tests. Here is an example of what I'm talking about:
class ObjectUnderTest
def calculate(a, b)
value = a.to_d / b
{
value: value
{
end
end
The test looks like this:
RSpec.describe ObjectUnderTest do
it "calculates the product of two values" do
o = ObjectUnderTest.new
expect(o.calculate(1, 3)).to eql({value: 0.333})
end
end
The problem is that 0.333 is a float and the actual value being included in the hash is a BigDecimal. If I change the line in the test to say something like:
expect(o.calculate(1, 3)).to eql({value: 0.333.to_d(3)})
... the test still fails A) because the precision is different, and B) in my actual code, I have several key-value pairs and I don't want to have to call k.to_d(some_precision) on all of the comparison hashes to get it to pass.
Is there a way to compare the values using something like a_value_with some range do I don't have to hard-code an exact number in there?
Floating point numbers are inexact (even to the point that (0.1 + 0.2) == 0.3
returns false), so you have to use matchers that allow for values near to your expected value rather than equal. RSpec's be_within(x).of(y)
(and its alias, a_value_within(x).of(y)
) is designed for matching floating point numbers. RSpec 3 also supports composable matchers and the match
matcher allows you to match nested hash/array data structures by putting matchers in place of values, so you can do this:
expect(o.calculate(1, 3)).to match(value: a_value_within(0.001).of(0.333))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With