【问题标题】:Why assert in @PactVerification?为什么在@PactVerification 中断言?
【发布时间】:2018-05-10 20:45:45
【问题描述】:

我不明白 @PactVerification 中 assert 的用法。对我来说,它更像是一种复杂的表达方式1 == 1。例如:

import static org.assertj.core.api.Assertions.assertThat;
public class PactConsumerDrivenContractUnitTest {
    @Rule
    public PactProviderRuleMk2 mockProvider
      = new PactProviderRuleMk2("test_provider", "localhost", 8080, this);
    @Pact(consumer = "test_consumer")
    public RequestResponsePact createPact(PactDslWithProvider builder) {            
        return builder
          .given("test GET ")
          .uponReceiving("GET REQUEST")
          .path("/")
          .method("GET")
          .willRespondWith()
          .body("{\"condition\": true, \"name\": \"tom\"}")
    }
    @Test
    @PactVerification()
    public void givenGet_whenSendRequest_shouldReturn200WithProperHeaderAndBody() {
        //when
        ResponseEntity<String> response
          = new RestTemplate().getForEntity(mockProvider.getUrl(), String.class);
        //then
        assertThat(response.getBody()).contains("condition", "true", "name", "tom");        
    }
}

所以我们首先在“createPact”中声明

body("{\"condition\": true, \"name\": \"tom\"}")

然后在givenGet_whenSendRequest_shouldReturn200WithProperHeaderAndBody 注释@PactVerification 我们这样做

assertThat(response.getBody()).contains("condition", "true", "name", "tom");

但是为什么呢?我们就是这么说的!据我所见,断言没有出现在生成的 Pact 文件中。它接缝没有任何目的?

除此之外,我认为合同测试的想法是减少对集成测试的需求,因为如果测试数据发生变化,它们可能会中断。但是这里我们仍然依赖测试数据。如果 Provider 中没有“Tom”,则测试将失败。我主要想测试合同是否损坏,而不是测试数据是否已更改。

【问题讨论】:

标签: pact pact-jvm


【解决方案1】:

给出的例子是一个人为的例子。在使用 Pact 的现实生活中,您不会这样做。您的 PactVerification 将调用协作方法/类/事物,该方法负责对您正在模拟的服务的外部调用。

所以你的断言是关于协作功能正在做什么。

例如。用户服务可能会创建具有某些属性的对象,您知道这些属性仅由该外部调用填充。

【讨论】:

  • 哦,我没想到。
【解决方案2】:

@PactVerification 测试方法中测试断言不是强制性的,但它仍然可能非常有用。例如。您可能会在 JSON 正文字符串中打错字,并且您将无法在测试中捕捉到它,它会破坏提供者的管道。在这种情况下,断言与生成的 Pact 文件无关,它们扮演着最后检查您刚刚定义的合约 (RequestResponsePact) 是否符合您的所有期望 (assertions) 的角色。

另外值得一提的是,您的消费者合同测试只有在提供者试图发布使您的期望被打破的更改时才应该中断。编写好的合约测试是消费者的责任。在您的示例中,您定义了以下期望:

@Pact(consumer = "test_consumer")
public RequestResponsePact createPact(PactDslWithProvider builder) {            
    return builder
        .given("test GET ")
        .uponReceiving("GET REQUEST")
            .path("/")
            .method("GET")
        .willRespondWith()
            .body("{\"condition\": true, \"name\": \"tom\"}")
}

只要condition == truename == tom,就会满足此合同。这是对响应的过度规范。您可以改为定义更灵活的响应 with PactDslJsonBody DSL

@Pact(consumer = "test_consumer")
public RequestResponsePact createPact(PactDslWithProvider builder) {
    final DslPart body = new PactDslJsonBody()
            .stringType("name", "tom")
            .booleanType("condition", true);

    return builder
            .given("test GET ")
            .uponReceiving("GET REQUEST")
                .path("/")
                .method("GET")
            .willRespondWith()
                .body(body)
            .toPact();
}

此片段将生成 Pact 文件,如:

{
    "provider": {
        "name": "providerA"
    },
    "consumer": {
        "name": "test_consumer"
    },
    "interactions": [
        {
            "description": "GET REQUEST",
            "request": {
                "method": "GET",
                "path": "/"
            },
            "response": {
                "status": 200,
                "headers": {
                    "Content-Type": "application/json; charset=UTF-8"
                },
                "body": {
                    "condition": true,
                    "name": "tom"
                },
                "matchingRules": {
                    "body": {
                        "$.name": {
                            "matchers": [
                                {
                                    "match": "type"
                                }
                            ],
                            "combine": "AND"
                        },
                        "$.condition": {
                            "matchers": [
                                {
                                    "match": "type"
                                }
                            ],
                            "combine": "AND"
                        }
                    }
                }
            },
            "providerStates": [
                {
                    "name": "test GET "
                }
            ]
        }
    ],
    "metadata": {
        "pact-specification": {
            "version": "3.0.0"
        },
        "pact-jvm": {
            "version": "3.5.10"
        }
    }
}

主要区别在于这个 Pact 文件使用matchingRules 来测试是否:

  • condition 字段的类型是boolean
  • name 字段的类型是String

对于字符串,如果需要,您还可以使用PactDslJsonBody.stringMatcher(name, regex, value) 方法。它允许您定义将使用当前字段值进行测试的正则表达式。

【讨论】:

  • 谢谢你的回答,我想我现在可能明白了一点。
  • 您应该真正在消费者合同测试中测试协作/接口代码(根据docs.pact.io/getting_started/testing-scope),而不是对原始的、收缩的 HTTP 响应提出断言。
猜你喜欢
  • 2012-10-15
  • 2010-11-08
  • 1970-01-01
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
  • 2021-01-08
  • 2013-02-25
  • 1970-01-01
相关资源
最近更新 更多