Java Spring云契约能否处理具有不同返回http状态码的重复请求?

Java Spring云契约能否处理具有不同返回http状态码的重复请求?,java,spring-boot,rest,spring-cloud-contract,Java,Spring Boot,Rest,Spring Cloud Contract,我正在开发一个小型REST服务,该服务处理一些数据并将其持久化(目前是Oracle,正在添加缓存) 我们开始使用Spring云契约框架处理消费者驱动的契约。我们很难为如何实现服务定义一个合同 我们有一个PUT端点,它在主体中接受一个输入字段,这是持久性中的主键。在我们的服务中,我们在数据库中查找该字段,如果它在那里,我们希望从数据库返回带有200状态码的现有数据,表示没有添加新记录。如果该值尚未在数据库中,那么我们有一些逻辑来为其生成数据并将数据插入数据库中。然后,我们希望返回201以表示数据已

我正在开发一个小型REST服务,该服务处理一些数据并将其持久化(目前是Oracle,正在添加缓存)

我们开始使用Spring云契约框架处理消费者驱动的契约。我们很难为如何实现服务定义一个合同

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

对于201案例,我们有一个有效的契约,因为当生成的JUnits运行时,没有数据存在,它返回201。但我们的消费者也希望签订200场景的合同

有没有一个好办法让合同执行两次相同的调用,这样我们就可以同时生成两种情况

我们的合同是这样的(精简但基本相同):


这里有两件事要讨论。让我们从第一个更重要的开始。进行合同测试时,不应访问数据库。如果您这样做,您不仅要测试控制器交互,还要测试所有其他层。在控制器中模拟服务,然后才运行契约测试


对于同一请求的第二个更改响应,您可以使用场景,即有状态存根。请查看此处的文档

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

所以我同意Marcin Grzejszczak的观点,你应该嘲笑这个服务。如果您真的坚持要为特定http代码定义一个契约,那么使用该模拟服务可以模拟该行为

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

但是,如果您只是在合同中添加“优先级: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
}
在生产者方面,当提供“9999999”值时,您必须模拟您的服务才能正确响应

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

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
}