6

我正在尝试使用 Spring-Cloud-Contract 定义一个 CDC 合同,如下所示:

org.springframework.cloud.contract.spec.Contract.make {
    request {
        method 'GET'
        url $(client(~/\/categories\?publication=[a-zA-Z-_]+?/), server('/categories?publication=DMO'))
    }
    response {
        status 200
        headers {
            header('Content-Type', 'application/json;charset=UTF-8')
        }
        body """\
            [{
                "code": "${value(client('DagKrant'), server(~/[a-zA-Z0-9_-]*/))}",
                "name": "${value(client('De Morgen Krant'), server(~/[a-zA-Z0-9_\- ]*/))}",
                "sections" : []
            },
            {
                "code": "${value(client('WeekendKrant'), server(~/[a-zA-Z0-9_-]*/))}",
                "name": "${value(client('De Morgen Weekend'), server(~/[a-zA-Z0-9_\- ]*/))}",
                "sections" : [
                    {
                    "id" : "${value(client('a984e824'), server(~/[0-9a-f]{8}/))}",
                    "name" : "${value(client('Binnenland'), server(~/[a-zA-Z0-9_\- ]*/))}"
                    }
                ]
            }]
        """
    }
}

在生成的测试中,这会导致以下断言:

DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).array().contains("code").matches("[a-zA-Z0-9_-]*");
assertThatJson(parsedJson).array().array("sections").contains("id").matches("([0-9a-f]{8})?");
assertThatJson(parsedJson).array().array("sections").contains("name").matches("[a-zA-Z0-9_\\- ]*");
assertThatJson(parsedJson).array().contains("name").matches("[a-zA-Z0-9_\\- ]*");

但是在我的测试中,我想允许 section 数组为空,就像第一个示例一样。现在,如果我的测试实现返回一个空的sections 数组,则生成的测试将失败,因为它找不到空数组的section id。

Parsed JSON [[{"code":"WeekendKrant","name":"De Morgen Weekend","sections":[]}]] 
doesn't match the JSON path [$[*].sections[*][?(@.id =~ /([0-9a-f]{8})?/)]]

我也尝试了 optional(),但唯一的区别是正则表达式包含一个“?” 在最后。JSON 断言仍然失败。

在存根中,两个结果都返回,但对于测试,我希望测试对两者都成功。测试断言是否纯粹在每个属性的最后一次出现时生成?数组上是否不可能有“可选()”之类的东西?

4

1 回答 1

5

在版本 1.0.3.RELEASE 之前,不可能进行这样的额外检查。从那个版本开始,您可以提供额外的匹配器 - http://cloud.spring.io/spring-cloud-static/spring-cloud-contract/1.0.3.RELEASE/#_dynamic_properties_in_matchers_sections。您可以匹配byType与尺寸相关的附加检查。

取自文档:

目前,我们仅支持具有以下匹配可能性的基于 JSON 路径的匹配器。对于 stubMatchers:

byEquality() - 通过提供的 JSON 路径从响应中获取的值需要等于合约中提供的值

byRegex(...​) - 通过提供的 JSON 路径从响应中获取的值需要匹配正则表达式

byDate() - 通过提供的 JSON 路径从响应中获取的值需要与 ISO 日期的正则表达式匹配

byTimestamp() - 通过提供的 JSON 路径从响应中获取的值需要匹配 ISO DateTime 的正则表达式

byTime() - 通过提供的 JSON 路径从响应中获取的值需要匹配 ISO 时间的正则表达式

对于 testMatchers:

byEquality() - 通过提供的 JSON 路径从响应中获取的值需要等于合约中提供的值

byRegex(...​) - 通过提供的 JSON 路径从响应中获取的值需要匹配正则表达式

byDate() - 通过提供的 JSON 路径从响应中获取的值需要与 ISO 日期的正则表达式匹配

byTimestamp() - 通过提供的 JSON 路径从响应中获取的值需要匹配 ISO DateTime 的正则表达式

byTime() - 通过提供的 JSON 路径从响应中获取的值需要匹配 ISO 时间的正则表达式

byType() - 通过提供的 JSON 路径从响应中获取的值需要与合同中响应正文中定义的类型相同。byType 可以采用闭包,您可以在其中设置 minOccurrence 和 maxOccurrence。这样你就可以断言集合的大小。

和例子:

Contract contractDsl = Contract.make {
request {
    method 'GET'
    urlPath '/get'
    body([
            duck: 123,
            alpha: "abc",
            number: 123,
            aBoolean: true,
            date: "2017-01-01",
            dateTime: "2017-01-01T01:23:45",
            time: "01:02:34",
            valueWithoutAMatcher: "foo",
            valueWithTypeMatch: "string"
    ])
    stubMatchers {
        jsonPath('$.duck', byRegex("[0-9]{3}"))
        jsonPath('$.duck', byEquality())
        jsonPath('$.alpha', byRegex(onlyAlphaUnicode()))
        jsonPath('$.alpha', byEquality())
        jsonPath('$.number', byRegex(number()))
        jsonPath('$.aBoolean', byRegex(anyBoolean()))
        jsonPath('$.date', byDate())
        jsonPath('$.dateTime', byTimestamp())
        jsonPath('$.time', byTime())
    }
    headers {
        contentType(applicationJson())
    }
}
response {
    status 200
    body([
            duck: 123,
            alpha: "abc",
            number: 123,
            aBoolean: true,
            date: "2017-01-01",
            dateTime: "2017-01-01T01:23:45",
            time: "01:02:34",
            valueWithoutAMatcher: "foo",
            valueWithTypeMatch: "string",
            valueWithMin: [
                1,2,3
            ],
            valueWithMax: [
                1,2,3
            ],
            valueWithMinMax: [
                1,2,3
            ],
    ])
    testMatchers {
        // asserts the jsonpath value against manual regex
        jsonPath('$.duck', byRegex("[0-9]{3}"))
        // asserts the jsonpath value against the provided value
        jsonPath('$.duck', byEquality())
        // asserts the jsonpath value against some default regex
        jsonPath('$.alpha', byRegex(onlyAlphaUnicode()))
        jsonPath('$.alpha', byEquality())
        jsonPath('$.number', byRegex(number()))
        jsonPath('$.aBoolean', byRegex(anyBoolean()))
        // asserts vs inbuilt time related regex
        jsonPath('$.date', byDate())
        jsonPath('$.dateTime', byTimestamp())
        jsonPath('$.time', byTime())
        // asserts that the resulting type is the same as in response body
        jsonPath('$.valueWithTypeMatch', byType())
        jsonPath('$.valueWithMin', byType {
            // results in verification of size of array (min 1)
            minOccurrence(1)
        })
        jsonPath('$.valueWithMax', byType {
            // results in verification of size of array (max 3)
            maxOccurrence(3)
        })
        jsonPath('$.valueWithMinMax', byType {
            // results in verification of size of array (min 1 & max 3)
            minOccurrence(1)
            maxOccurrence(3)
        })
    }
    headers {
        contentType(applicationJson())
    }
}
}

和生成测试的示例(用于断言大小的部分)

assertThat((Object) parsedJson.read("$.valueWithMin")).isInstanceOf(java.util.List.class);
assertThat(parsedJson.read("$.valueWithMin", java.util.Collection.class).size()).isGreaterThanOrEqualTo(1);
assertThat((Object) parsedJson.read("$.valueWithMax")).isInstanceOf(java.util.List.class);
assertThat(parsedJson.read("$.valueWithMax", java.util.Collection.class).size()).isLessThanOrEqualTo(3);
assertThat((Object) parsedJson.read("$.valueWithMinMax")).isInstanceOf(java.util.List.class);
assertThat(parsedJson.read("$.valueWithMinMax", java.util.Collection.class).size()).isStrictlyBetween(1, 3);
于 2017-01-18T14:08:20.067 回答