Java – hamcrest matcher compares the double value of JSON
I am using the hamcrest corematcher class as part of the spring test integration test My JSON looks like:
{"data":[{"distanceInMiles":4,"id":"f97236ba-f4ef-4...
My integration tests look like:
double miles = 4.0 Activity a = new BasicActivity(miles); this.activityManager.add(a); // A mock activity manager (in-memory) ... this.mockmvc.perform(get("/").accept("application/json")) .andExpect(jsonPath("$.data[0].distanceInMiles",is(miles)))
However, the assertion failed:
java.lang.AssertionError: JSON path "$.data[0].distanceInMiles" Expected: is <4.0> but: was <4> at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
I know there is a separate iscloseto matcher: http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/number/IsCloseTo.html , but use it like this:
.andExpect(jsonPath("$.data[0].distanceInMiles",closeTo(miles,0)))
Causes a strange error:
java.lang.AssertionError: JSON path "$.data[0].distanceInMiles" Expected: a numeric value within <0.0> of <4.0> but: was a java.lang.Integer (<4>) at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
I want to avoid including some kind of error - I want to return a value of exactly 4, I just don't care how many trailing zeros I include
Solution
The problem is that matching is performed on integers, not on double values
You correctly gave matcher < < double > Spring uses jayway to parse JSON, and your JSON path will be evaluated as an integer object Matching will fail because integer and double are always unequal
Therefore, you need to change the matcher to ((int) miles)
This is even more problematic if you don't control the JSON you're getting and distanceinmiles may change Jayway parses "4" as an integer, but it parses "4.0" as a double In this case, you will have to implement your own matcher by extending typesafematcher to handle integer and double objects This will be a simple implementation:
class NumberMatcher extends TypeSafeMatcher<Number> { private double value; public NumberMatcher(double value) { this.value = value; } @Override public void describeTo(Description description) { // some description } @Override protected boolean matchesSafely(Number item) { return item.doubleValue() == value; } }
It matches any number by comparing their double value with the known double value