6

I want to do an assertion where the actual value is within either a fixed +/- value of the expected value or a percent +/- value of the expected value.

While googling I noticed that NUnit had a nice syntax for that :

Assert.That( 5.5, Is.EqualTo( 5 ).Within(0.075);
Assert.That( 5.5, Is.EqualTo( 5 ).Within(1.5).Percent;

Does JUnit or Hamcrest have something similar I can use? If not, is there a nice way to express this behavior?

Mureinik
  • 297,002
  • 52
  • 306
  • 350
Krish Srinivasan
  • 568
  • 1
  • 6
  • 14

2 Answers2

9

The short answer - yes.

Old fashioned org.junit.Assert has a method assertEquals(java.lang.String message, float expected, float actual, float delta), and a bunch of a similar method for doubles, overloaded variants wihout the message, and similar implementations of assertArrayEquals.

If you want to use Hamcrest, the closeTo matcher is what you're looking for.

EDIT:
To address the question in the comments about percentages - there isn't an out-of-box matcher for this, but you can gimmy-rig something yourself by dividing the two, and making sure they are between the desired ratio and its inverse. To take the example from the OP:

float expected = 5.0;
float actual = 5.5
float ratio = 1.0075;
float inverse = 1/ratio;

float div = actual/expected;

assertThat(div, allOf(greaterThan(inverse), lessThan(ratio)));

It's a bit (well, a lot) clunky, but it should do the trick.

Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • The closeTo matcher does compare two values with a fixed tolerance value. Isnt there something that also does percentage tolerances. – Krish Srinivasan Oct 28 '14 at 18:55
  • @algorithmic Unfortunately there isn't an easy, out-of-the-box way to do this, but see my edit for a solution. – Mureinik Oct 28 '14 at 19:07
  • the allOf, greaterThan and lessThan should do the trick provided I calculate the the percentage value of the expected value that I am expecting the tolerance to be in and use that. If I calculated the percentage value that I am willing to tolerate I guess I could also use closeTo. I am marking your answer since this is pretty much what I want. – Krish Srinivasan Oct 28 '14 at 19:19
4

Complementing Mureinik's answer:

To assert with a relative tolerance / percentage, you can just multiply:

    double closeTo5 = 4.6;
    double relativeTolerance = 0.1;
    double expected = 5;

    assertThat(closeTo5, 
        is(closeTo(expected, expected*relativeTolerance)));

Or, if you want to get fancy, write your own matcher (which is not hard)...

sleske
  • 81,358
  • 34
  • 189
  • 227
  • I think the call to "is()" can be omitted, although some might find it more readable that way. – DPM Jan 13 '18 at 19:54