Yeah, I know. If you're using a double then you probably want an exact number.

But sometimes a ballpark result will do.

In other words, if your unit test returns something within .03 of the desired result, that's good enough.

Fortunately, you can write JUnit test cases that handle that type of scenario. In this guide, I'll show you how.

The Use Case

For this use case, you want to handle something very important. You want to check the air speed of European swallow in flight.

And it's important you know that or you could find yourself in a lot of trouble when you reach the Bridge of Death.

But you don't need to get the exact speed of the swallow. Just within .01 of furlongs per minute.

Of course, everybody knows that a European swallow travels at about .055 furlongs per minute. So that's the number we're aiming for here.

With that in mind, let's get coding.

The Swallow Class

First up: the Swallow class.

public class Swallow {

    public double getSpeed() {
        Random random = new Random();

        final double speed = random
                .doubles(.05d,.06d)
                .findFirst()
                .getAsDouble();

        return speed;
    }
}

There are probably a few ways to skin this cat, but here I've decided to go with generating a random number that lands between .05 and .06.

It should average out to .055 so that's good enough for this project. And close enough for government work.

The class only has one method: getSpeed(). That's the beast that gets you the random number.

Of course, it will be different every time. That's the nature of random numbers, after all. And the nature of this tutorial as well.

The Test

Now it's time to make sure that this swallow is travelling at the expected speed of .055 furlongs per minute.

Write a simple test:

public class SwallowTest {

    @Test
    public void testSwallowSpeed() {
        final Swallow swallow = new Swallow();
        final double speed = swallow.getSpeed();

        assertEquals(.055d, speed);
    }
}

That's a fairly straightforward test. The code above starts by instantiating the Swallow class that you created above.

Then, it calls getSpeed() to get the speed of the swallow.

And, finally, it checks the expected value of the speed (.055 as a double) against the actual speed. 

Now run it. 

Welp, that sucks. It failed.

Here's what I got:

org.opentest4j.AssertionFailedError: 
Expected :0.055
Actual   :0.05258627827077087
<Click to see difference>

But your "Actual" number might be (and almost certainly is) a little different.

Why is that? Because it's a random number. You shouldn't expect to get the same number I got.

So that test failed.

Fortunately, though, you can fix it.

Fixing It

Have another look at that assertEquals() method above. You'll notice that there are only two parameters in it: the expected value and the actual value.

But when you're comparing doubles, you can throw in a third parameter. Really.

Some folks call that third parameter the epsilon. Others call it the delta.

It's all Greek to me.

Anyhoo, that third parameter lets you set the margin of error. So let's use it:

public class SwallowTest {

    @Test
    public void testSwallowSpeed() {
        final Swallow swallow = new Swallow();
        final double speed = swallow.getSpeed();

        assertEquals(.055d, speed, .01d);
    }
}

That code is identical to the code you saw above except that it's using a third parameter in assertEquals().

That third parameter is set to the value of .01 as a double. That means the value of speed can be the expected value (.055) plus or minus .01.

So a value from .045 to .065 wins. And that's well within the range specified in the random number generator (it went from .05 to .06).

Now run the code again. It works.

Wrapping It Up

You don't have to box yourself in to exact numbers when unit testing with doubles. Feel free to test with margins of error.

Now it's up to you to add what you've learned here to your own unit tests. Try your own variations and ballpark figures.

Have fun!

Photo by Pixabay: https://www.pexels.com/photo/abstract-accuracy-accurate-aim-262438/