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 对象。匹配将失败,因为 IntegerDouble 始终不相等。

因此,您需要将 Matcher 更改为 is((int) miles)

如果你不控制你得到的 JSON 并且 distanceInMiles 可能会改变,这更有问题。 Jayway 会将 "4" 解析为 Integer,但会将 "4.0" 解析为 Double。在这种情况下,您将必须通过扩展 TypeSafeMatcher 来实现自己的 Matcher 来处理 IntegerDouble 对象。这将是一个简单的实现:

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));