带有 Hamcrest 和 Rest Assured 以及 JSON 路径的黄瓜数据表

问题描述

我在 Gherkin 中有一个类似于以下的步骤:

    And the date range options are correct
      | startDate  | endDate    | isDefault | isCurrent |
      | 2020-03-02 | 2021-03-01 | false     | false     |
      | 2019-03-02 | 2020-03-01 | false     | false     |

在步骤定义类中,我尝试使用 Rest Assured 和 Hamcrest 来验证 JSON 响应中的日期范围。

    @And("the date range options are correct")
    public void validateDateranges(DataTable expectedDateranges) {
        String response = getJSONResponse();
        List<Map<String,Object>> expected = expectedDateranges.asMaps(String.class,Object.class);
        assertthat("Date Ranges are correct",from(response).get("daterangeOptions"),equalTo(expected));
    }

但是,这失败并出现以下错误

Expected: <[{startDate=2020-03-02,endDate=2021-03-01,isDefault=false,isCurrent=false},{startDate=2019-03-02,endDate=2020-03-01,{startDate=2018-03-02,endDate=2019-03-01,endDate=2018-06-17,isDefault=true,{startDate=2017-03-02,endDate=2018-03-01,{startDate=2016-03-02,endDate=2017-03-01,{startDate=2015-08-18,endDate=2016-03-01,isCurrent=false}]>
     but: was <[{startDate=2020-03-02,isCurrent=false}]>
    at org.hamcrest.MatcherAssert.assertthat(MatcherAssert.java:20)
    at scenarios.pagination.AccrualLog.validateDateranges(AccrualLog.java:80)
    at ✽.the date range options are correct(file:///.../accrualLog.feature:7)

考虑到这些值看起来都是正确的,我认为这是由于数据类型不匹配 - 布尔字段从 DataTable 作为字符串返回。

除了使用类来表示日期范围之外,还有什么方法可以解决这个问题吗?

解决方法

我找到了解决方案。最后,我创建了自己的 Matcher 实现来检查 Cucumber DataTables:

public class DataTableMatcher extends BaseMatcher<Object> {

    private final List<Map<String,String>> expectedValues;

    public DataTableMatcher(Object expectedValue) {
        this.expectedValues = ((DataTable) expectedValue).asMaps();
    }

    public boolean matches(Object o) {
        List<?> actual = (List<?>) o;
        List<Map<String,String>> actualValues = actual.stream().map(this::castRow).collect(Collectors.toList());
        return expectedValues.equals(actualValues);
    }

    private Map<String,String> castRow(Object row) {
        Map<String,String> result = new HashMap<>();
        Map<?,?> cast = (Map<?,?>) row;
        for (Object column : cast.keySet()) {
            result.put(column.toString(),cast.get(column).toString());
        }
        return result;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("It to be right"); //TODO more helpful error message
    }
    
    public static Matcher<Object> dataTablesMatch(Object t) {
        return new DataTableMatcher(t);
    }
}

然后我可以这样使用它:

    @And("the date range options are correct")
    public void validateDateRanges(DataTable expectedDateRanges) {
        String response = getJSONResponse();
        assertThat("Date Ranges are correct",from(response).get("dateRangeOptions"),dataTablesMatch(expectedDateRanges));
    }

这有效。不过,我很想知道是否有更优雅的解决方案。