java - Spring Cloud Contracts可以处理具有不同返回http状态码的重复请求吗?

标签 java spring-boot rest spring-cloud-contract

我正在开发一个小型 REST 服务,用于处理一些数据并保留它(目前是 Oracle,正在添加缓存)。

我们开始使用 Spring Cloud Contract 框架处理消费者驱动的合约。我们在定义一份关于我们打算如何实现服务的契约(Contract)时遇到了困难。

我们有一个 PUT 端点,它在正文中接受一个输入字段,这是我们持久性的主键。在我们的服务中,我们在数据库中查找该字段,如果存在,我们希望从数据库返回现有数据,状态代码为 200,表示没有添加新记录。如果该值尚未存在于数据库中,那么我们有一些逻辑来为其生成数据并将数据插入数据库中。然后我们想返回 201 来表示数据已创建。

我们有一个针对 201 场景的工作合约,因为当生成的 JUnit 运行时,不存在数据并且它返回 201。但是我们的消费者也想要一个针对 200 场景的合约。

是否有一个好方法让合约执行相同的调用两次,以便我们可以生成这两种情况?

我们的契约(Contract)如下所示(精简但本质相同):

Contract.make {
    name("givenValidInputs_returnDataAndCreatedStatus")
    request {
        method 'PUT'
        url "/path/to/resource"
        headers {
            contentType("application/json")
        }
        body(
                "primaryKey": $(p('1234567890123456'), c(regex('^[0-9]+$')))
        )
    }
    response {
        status 201
        body(
                "generatedValue": $(p(regex('^[0-9a-zA-Z]+$')), c('abc123'))   
        )
    }
}

最佳答案

契约(Contract)测试旨在测试端点的技术握手。它不应该用于测试(有状态)行为。 200 和 201 之间的 http 代码差异可以被视为一种边缘情况,但在我看来,这是一种语义差异。

所以我同意 Marcin Grzejszczak 的观点,你应该 mock 这项服务。如果您确实坚持为特定的 http 代码制定契约定义,那么通过该模拟服务,您可以模拟该行为。

除了场景之外,您还可以指定一个特定的主键来表示“已存在”的情况。 唯一的问题是,当消费者在调用 stub 时提供“99999999”时,它将在两个合约上匹配(因为该值也与 201 合约中提供的正则表达式匹配)。

如果您只是将“priority: 1”添加到合约中,则在提供特定属性时,200 合约将优先于 201 合约。

Contract.make {
    name("when put existing, expect 200")
    request {
        method 'PUT'
        url "/path/to/resource"
        headers {
            contentType("application/json")
        }
        body(
                "primaryKey": "99999999"
        )
    }
    response {
        status 200
        body(
                "generatedValue": $(p(regex('^[0-9a-zA-Z]+$')), c('abc123'))   
        )
    }
    priority 1
}

在生产者方面,您必须模拟您的服务才能在提供“99999999”值时正确响应。

我个人认为我不会在合约测试中包含此 http 代码,因为它代表有状态行为,因此是语义的,在我看来不是技术连接要求。在双方方面,我都会在非集成单元测试中测试给定情况的行为。尽管在这种情况下有时很难将句法与语义分开。

关于java - Spring Cloud Contracts可以处理具有不同返回http状态码的重复请求吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60457462/

相关文章:

java - scala 宏注释的注释是什么?或者宏应用了多少次

SPRING BOOT 使用 Jasig CAS 配置

node.js - 前端和后端的 JWT Token 策略

android - 在 retrofit 2 和 gson 中无法获得特殊字符

json - Elasticsearch delete-by-query 返回成功但记录仍然存在?

java - Android 不启动默认 Activity (MainActivity)

Java ArrayList复制更改原始值

java - 从整数行中获取元素java

java - 在 Spring Boot 中使用后置方法保存多个实体时的无限循环

spring-boot - Spring Boot v1.2 由于 RepositoryInformation 导致 AbstractMethodError