Hamcrest comparison comparing double value from JSON

I use the Hamcrest CoreMatcher classes as part of the spring-test integration tests. My JSON looks like this:

 {"data":[{"distanceInMiles":4,"id":"f97236ba-f4ef-4... 

And my integration test is as follows:

 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 statement fails:

 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 that there is a separate IsCloseTo : http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/number/IsCloseTo.html , but using it like this:

 .andExpect(jsonPath("$.data[0].distanceInMiles", closeTo(miles, 0))) 

leads to 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 was hoping to avoid the need to include some kind of error - I want the return value to be exactly 4 , I just don't care how many zeros are included.

+7
java json spring spring-test hamcrest
source share
2 answers

The problem is that the match is done on Integer and not on double values.

You give Matcher<Double> correctly. Spring uses Jayway under the hood to parse JSON, and your JSON path will be evaluated as an Integer object. Matching will fail because Integer and Double always unequal.

So you need to change Matcher to is((int) miles) .

If you do not control the JSON that you receive, and distanceInMiles may change, this is more problematic. Jayway will parse "4" as an Integer , but it will parse "4.0" as a Double . In this case, you will have to implement your own Matcher , which processes Integer and Double objects, expanding TypeSafeMatcher . 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 , comparing their double value with a known double value.

+2
source share

I found out that it compares as a float by default, so try something like:

 .body("field_with_double_value",is(100.0f)); 
+1
source share

All Articles