Hamcrest 匹配器比较来自 JSON 的双精度值
Hamcrest matcher comparing double value from JSON
我正在使用 Hamcrest CoreMatcher
类 作为 spring-test
集成测试的一部分。我的 JSON 看起来像:
{"data":[{"distanceInMiles":4,"id":"f97236ba-f4ef-4...
我的集成测试如下所示:
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)))
然而,断言失败:
java.lang.AssertionError: JSON path "$.data[0].distanceInMiles"
Expected: is <4.0>
but: was <4>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
我知道这里有一个单独的 IsCloseTo
匹配器:http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/number/IsCloseTo.html,但可以这样使用它:
.andExpect(jsonPath("$.data[0].distanceInMiles", closeTo(miles, 0)))
导致一个奇怪的错误:
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)
我希望避免包含某种错误 - 我 想要 返回值正好是 4
,我只是不在乎有多少包括尾随零。
问题是匹配是在 Integer
上执行的,而不是在双精度值上执行的。
您给出的 Matcher<Double>
是正确的。 Spring 在引擎盖下使用 Jayway 来解析 JSON 并且您的 JSON 路径将被评估为 Integer
对象。匹配将失败,因为 Integer
和 Double
始终不相等。
因此,您需要将 Matcher
更改为 is((int) miles)
。
如果你不控制你得到的 JSON 并且 distanceInMiles
可能会改变,这更有问题。 Jayway 会将 "4"
解析为 Integer
,但会将 "4.0"
解析为 Double
。在这种情况下,您将必须通过扩展 TypeSafeMatcher
来实现自己的 Matcher
来处理 Integer
和 Double
对象。这将是一个简单的实现:
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;
}
}
它通过将双精度值与已知双精度值进行比较来匹配任何 Number
。
我发现默认情况下比较的是浮点数,所以试试这样的东西:
.body("field_with_double_value",is(100.0f));
我正在使用 Hamcrest CoreMatcher
类 作为 spring-test
集成测试的一部分。我的 JSON 看起来像:
{"data":[{"distanceInMiles":4,"id":"f97236ba-f4ef-4...
我的集成测试如下所示:
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)))
然而,断言失败:
java.lang.AssertionError: JSON path "$.data[0].distanceInMiles"
Expected: is <4.0>
but: was <4>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
我知道这里有一个单独的 IsCloseTo
匹配器:http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/number/IsCloseTo.html,但可以这样使用它:
.andExpect(jsonPath("$.data[0].distanceInMiles", closeTo(miles, 0)))
导致一个奇怪的错误:
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)
我希望避免包含某种错误 - 我 想要 返回值正好是 4
,我只是不在乎有多少包括尾随零。
问题是匹配是在 Integer
上执行的,而不是在双精度值上执行的。
您给出的 Matcher<Double>
是正确的。 Spring 在引擎盖下使用 Jayway 来解析 JSON 并且您的 JSON 路径将被评估为 Integer
对象。匹配将失败,因为 Integer
和 Double
始终不相等。
因此,您需要将 Matcher
更改为 is((int) miles)
。
如果你不控制你得到的 JSON 并且 distanceInMiles
可能会改变,这更有问题。 Jayway 会将 "4"
解析为 Integer
,但会将 "4.0"
解析为 Double
。在这种情况下,您将必须通过扩展 TypeSafeMatcher
来实现自己的 Matcher
来处理 Integer
和 Double
对象。这将是一个简单的实现:
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;
}
}
它通过将双精度值与已知双精度值进行比较来匹配任何 Number
。
我发现默认情况下比较的是浮点数,所以试试这样的东西:
.body("field_with_double_value",is(100.0f));