I'm using the Hamcrest CoreMatcher
classes as part of spring-test
integration tests. My JSON looks like:
{"data":[{"distanceInMiles":4,"id":"f97236ba-f4ef-4...
And my integration test looks 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 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's a separate IsCloseTo
matcher here: http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/number/IsCloseTo.html, but using it like so:
.andExpect(jsonPath("$.data[0].distanceInMiles", closeTo(miles, 0)))
results in 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 having to include some kind of error - I want the returned value to be exactly 4
, I just don't care how many trailing zeroes are included.
The problem is that the match is performed on Integer
s and not on double values.
You are correctly giving a Matcher<Double>
. Spring uses Jayway under the hood for parsing the JSON and your JSON path will be evaluated as an Integer
object. The matching will fail because an Integer
and a Double
are always unequal.
As such, you need to change your Matcher
to is((int) miles)
.
If you don't control the JSON you are getting and the distanceInMiles
might 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
that handles both Integer
and Double
objects by extending TypeSafeMatcher
. This would 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 to a known double value.
I found out that by default is comparing as float, so try something like:
.body("field_with_double_value",is(100.0f));
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