Spring 当 body 是一个列表时,Cloud Contract 生成带有空 body 的契约
Spring Cloud Contract generates Pacts with empty body when the body is a list
我正在尝试从 spring 云合同生成协议,如 documentation 所示。它只在响应 body 根是 json 时才工作,但是当我试图生成一个 return 一个 json 数组的协议时,它会生成一个空的body。我尝试使用 groovy 字符串格式 """[{}...]"""
的 dsl 并使用 DslProperty [value()...]
。这是我的合同:
使用字符串格式
Contract.make {
description "should return a list of dummy object with dummy value. Generates pact with empty json"
request {
method GET()
url("/dummy")
}
response {
body("""[{"value": "Hi! I'm a dummy object ;)"}]""")
headers {
contentType applicationJson()
}
status 200
}}
使用 DslProperty
Contract.make {
description "should return a list of dummy object with dummy value. Generates pact with empty body list"
request {
method GET()
url("/dummy")
}
response {
body([value(value: "Hi! I'm a dummy object ;)")])
headers {
contentType applicationJson()
}
status 200
}}
这是在 target/pacts
处生成的文件
{
"provider": {
"name": "Provider"
},
"consumer": {
"name": "Consumer"
},
"interactions": [
{
"description": "should return a list of dummy object with dummy value. Generates pact with empty body list",
"request": {
"method": "GET",
"path": "/dummy"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": [
],
"matchingRules": {
"header": {
"Content-Type": {
"matchers": [
{
"match": "regex",
"regex": "application/json.*"
}
],
"combine": "AND"
}
}
}
}
},
{
"description": "should return a list of dummy object with dummy value. Generates pact with empty json",
"request": {
"method": "GET",
"path": "/dummy"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": {
},
"matchingRules": {
"header": {
"Content-Type": {
"matchers": [
{
"match": "regex",
"regex": "application/json.*"
}
],
"combine": "AND"
}
}
}
}
}
],
"metadata": {
"pactSpecification": {
"version": "3.0.0"
},
"pact-jvm": {
"version": "3.5.23"
}
}}
我正在使用以下版本
<spring-cloud.version>Hoxton.BUILD-SNAPSHOT</spring-cloud.version>
<spring-cloud-contract.version>2.0.1.RELEASE</spring-cloud-contract.version>
<pact-jvm-provider-maven.version>3.5.23</pact-jvm-provider-maven.version>
这就是我的插件配置
<!-- SCC to pact see https://cloud.spring.io/spring-cloud-contract/reference/html/howto.html#how-to-generate-pact-from-scc-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>convert-dsl-to-pact</id>
<phase>process-test-classes</phase>
<configuration>
<classpathScope>test</classpathScope>
<mainClass>
org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer
</mainClass>
<arguments>
<argument>
org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter
</argument>
<argument>${project.basedir}/target/pacts</argument>
<argument>
${project.basedir}/src/test/resources/contracts
</argument>
</arguments>
</configuration>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
</plugin>
在调试插件时,我看到分别发生的事情是:
- 当将 body 声明为 “”” [{...}] “””
时,Pact 转换器假定 body 是一个 String
实例,因此它在 org.springframework.cloud.contract.verifier.spec.pact.BodyConverter
处通过遍历方法。由于它以 [
开头,因此不会被解析。
org.springframework.cloud.contract.verifier.spec.pact.BodyConverter
private static DslPart traverse(Object value, DslPart parent, Closure dslPropertyValueExtractor) {
...
if (v instanceof String) {
v = v.trim()
if (v.startsWith("{") && v.endsWith("}")) {
try {
v = jsonSlurper.parseText(v as String)
}
catch (JsonException ex) { /*it wasn't a JSON string after all...*/
}
}
}
...
另一方面,当使用 DslProperty
浏览插件代码时,我有一个 object 像 [DslProperty{clientValue=DslProperty}]
。第一个 DslProperty 正在被提取,但由于内容是另一个 DslProperty 并且没有递归提取,我最终得到一个空的 body 因为 v
不是 Gstring
、String
、Number
、Map
、Collection
。所以我又得到一个空的 body 。
org.springframework.cloud.contract.verifier.spec.pact.BodyConverter
private static void processCollection(Collection values, PactDslJsonArray jsonArray, Closure dslPropertyValueExtractor) {
values.forEach({
Object v = it
if (v instanceof DslProperty) {
v = dslPropertyValueExtractor(v)
}
if (v instanceof GString) {
v = ContentUtils.extractValue(v, dslPropertyValueExtractor)
}
if (v == null) {
jsonArray.nullValue()
}
else if (v instanceof String) {
jsonArray.string(v)
}
else if (v instanceof Number) {
jsonArray.number(v)
}
else if (v instanceof Map) {
PactDslJsonBody current = jsonArray.object()
traverse(v, current, dslPropertyValueExtractor)
current.closeObject()
}
else if (v instanceof Collection) {
PactDslJsonArray current = jsonArray.array()
traverse(v, current, dslPropertyValueExtractor)
current.closeArray()
}
})
}
我已经在 https://github.com/brjt23/contract-to-pact/tree/master 上发布了一个示例,以防需要有关我如何构建项目的更多信息。
我在定义我的 groovy 合同文件时有什么地方做错了吗?我想我误解了应该如何定义响应 body。
您需要像这样在体内创建一个 groovy 对象数组:
body([
[value: "Object1"],
[value: "Object2"]
])
这样 spring 云合同将生成您的合同所需的正确代码。
我正在尝试从 spring 云合同生成协议,如 documentation 所示。它只在响应 body 根是 json 时才工作,但是当我试图生成一个 return 一个 json 数组的协议时,它会生成一个空的body。我尝试使用 groovy 字符串格式 """[{}...]"""
的 dsl 并使用 DslProperty [value()...]
。这是我的合同:
使用字符串格式
Contract.make {
description "should return a list of dummy object with dummy value. Generates pact with empty json"
request {
method GET()
url("/dummy")
}
response {
body("""[{"value": "Hi! I'm a dummy object ;)"}]""")
headers {
contentType applicationJson()
}
status 200
}}
使用 DslProperty
Contract.make {
description "should return a list of dummy object with dummy value. Generates pact with empty body list"
request {
method GET()
url("/dummy")
}
response {
body([value(value: "Hi! I'm a dummy object ;)")])
headers {
contentType applicationJson()
}
status 200
}}
这是在 target/pacts
处生成的文件{
"provider": {
"name": "Provider"
},
"consumer": {
"name": "Consumer"
},
"interactions": [
{
"description": "should return a list of dummy object with dummy value. Generates pact with empty body list",
"request": {
"method": "GET",
"path": "/dummy"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": [
],
"matchingRules": {
"header": {
"Content-Type": {
"matchers": [
{
"match": "regex",
"regex": "application/json.*"
}
],
"combine": "AND"
}
}
}
}
},
{
"description": "should return a list of dummy object with dummy value. Generates pact with empty json",
"request": {
"method": "GET",
"path": "/dummy"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"body": {
},
"matchingRules": {
"header": {
"Content-Type": {
"matchers": [
{
"match": "regex",
"regex": "application/json.*"
}
],
"combine": "AND"
}
}
}
}
}
],
"metadata": {
"pactSpecification": {
"version": "3.0.0"
},
"pact-jvm": {
"version": "3.5.23"
}
}}
我正在使用以下版本
<spring-cloud.version>Hoxton.BUILD-SNAPSHOT</spring-cloud.version>
<spring-cloud-contract.version>2.0.1.RELEASE</spring-cloud-contract.version>
<pact-jvm-provider-maven.version>3.5.23</pact-jvm-provider-maven.version>
这就是我的插件配置
<!-- SCC to pact see https://cloud.spring.io/spring-cloud-contract/reference/html/howto.html#how-to-generate-pact-from-scc-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>convert-dsl-to-pact</id>
<phase>process-test-classes</phase>
<configuration>
<classpathScope>test</classpathScope>
<mainClass>
org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer
</mainClass>
<arguments>
<argument>
org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter
</argument>
<argument>${project.basedir}/target/pacts</argument>
<argument>
${project.basedir}/src/test/resources/contracts
</argument>
</arguments>
</configuration>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
</plugin>
在调试插件时,我看到分别发生的事情是:
- 当将 body 声明为 “”” [{...}] “””
时,Pact 转换器假定 body 是一个 String
实例,因此它在 org.springframework.cloud.contract.verifier.spec.pact.BodyConverter
处通过遍历方法。由于它以 [
开头,因此不会被解析。
org.springframework.cloud.contract.verifier.spec.pact.BodyConverter
private static DslPart traverse(Object value, DslPart parent, Closure dslPropertyValueExtractor) {
...
if (v instanceof String) {
v = v.trim()
if (v.startsWith("{") && v.endsWith("}")) {
try {
v = jsonSlurper.parseText(v as String)
}
catch (JsonException ex) { /*it wasn't a JSON string after all...*/
}
}
}
...
另一方面,当使用 DslProperty
浏览插件代码时,我有一个 object 像 [DslProperty{clientValue=DslProperty}]
。第一个 DslProperty 正在被提取,但由于内容是另一个 DslProperty 并且没有递归提取,我最终得到一个空的 body 因为 v
不是 Gstring
、String
、Number
、Map
、Collection
。所以我又得到一个空的 body 。
org.springframework.cloud.contract.verifier.spec.pact.BodyConverter
private static void processCollection(Collection values, PactDslJsonArray jsonArray, Closure dslPropertyValueExtractor) {
values.forEach({
Object v = it
if (v instanceof DslProperty) {
v = dslPropertyValueExtractor(v)
}
if (v instanceof GString) {
v = ContentUtils.extractValue(v, dslPropertyValueExtractor)
}
if (v == null) {
jsonArray.nullValue()
}
else if (v instanceof String) {
jsonArray.string(v)
}
else if (v instanceof Number) {
jsonArray.number(v)
}
else if (v instanceof Map) {
PactDslJsonBody current = jsonArray.object()
traverse(v, current, dslPropertyValueExtractor)
current.closeObject()
}
else if (v instanceof Collection) {
PactDslJsonArray current = jsonArray.array()
traverse(v, current, dslPropertyValueExtractor)
current.closeArray()
}
})
}
我已经在 https://github.com/brjt23/contract-to-pact/tree/master 上发布了一个示例,以防需要有关我如何构建项目的更多信息。
我在定义我的 groovy 合同文件时有什么地方做错了吗?我想我误解了应该如何定义响应 body。
您需要像这样在体内创建一个 groovy 对象数组:
body([
[value: "Object1"],
[value: "Object2"]
])
这样 spring 云合同将生成您的合同所需的正确代码。