我正在开发一个小型 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/