【问题标题】:Spring Cloud Contract generates Pacts with empty body when the body is a list当正文为列表时,Spring Cloud Contract 生成正文为空的 Pact
【发布时间】:2020-04-27 22:30:57
【问题描述】:

我正在尝试根据 documentation 所示的 Spring Cloud 合约生成协议。它仅在响应主体根为 json 时才起作用,但是当我尝试生成一个返回 jsons 数组的协定时,它会生成一个空主体。我尝试过使用字符串格式"""[{}...]""" 的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 浏览插件代码时,我有一个像[DslProperty{clientValue=DslProperty}] 这样的对象。第一个 DslProperty 正在被提取,但由于内容是另一个 DslProperty 并且没有递归提取,我最终得到一个空主体,因为v 不是Gstring、String、Number、@987654341 的实例@,Collection。所以我又得到了一个空的身体。

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 合同文​​件时我做错了什么吗?我想我对如何定义响应主体有误解。

【问题讨论】:

    标签: pact spring-cloud-contract


    【解决方案1】:

    你需要像这样在你的 body 中创建一个 groovy 对象数组:

    body([ [value: "Object1"], [value: "Object2"] ])

    这样,Spring Cloud 合约将生成您的合约所需的正确代码。

    【讨论】:

    • mm 我明白了,所以我必须使用 [] 声明而不是 value()。这对我有用,谢谢
    猜你喜欢
    • 2018-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-18
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    相关资源
    最近更新 更多