如何在数据 returns 项有或没有子项时验证 PACT(已填充或不存在现有数组)
How to verify PACT when data returns items with or without children (filled in or no existing array)
我正在使用 PACT 和 Java 进行合同测试,我的问题是我有一个 api 项目可能会像这样出现:
[
{
"programCode": "ELA_NGL_G7_TX",
"contentResources": [
{
"tocPosition": 1827,
"contentIdentifier": "l_6bf0783e-8499-4f6c-9f9b-c8fbdc8dcf6b_e5f25016-e2fa-4223-8969-2004c644917d"
},
{
"tocPosition": 1828,
"contentIdentifier": "l_192af774-54b9-4280-87e9-71f2b86a7d4d_e5f25016-e2fa-4223-8969-2004c644917d",
"skills": [
{
"skillId": "ae836bd9-4758-4665-b3f8-8339313363e3",
"spineId": "63c2b7d0-cd69-4e8a-9761-c90623104b8c"
}
]
}
]
正如您所见,有时内部技能数组会出现,而其他则不会出现,并且不确定如何将此场景纳入我的消费者测试。我的意思是,如果响应有或没有技能数组取决于特定的参数,我可以进行两个不同的测试,这可能没问题,但这里它们来自同一个调用。所以我想我需要的是类似 if else 的东西,如果存在 skills 数组,那么我会断言它的内部子项,否则就忽略它。
这是我的消费者:
@ExtendWith(PactConsumerTestExt.class)
public class PublishContractWithTocGetSummaryTest {
Map<String, String> headers = new HashMap<>();
String getRecommendations = "/toc/getsummary/ELA_NGL_G7_TX";
@Pact(provider = "CRS-METADATA-FILTERING-SERVICE", consumer = "CRS-TOC-RECOMMENDER")
public RequestResponsePact createPact(PactDslWithProvider builder) throws IOException {
headers.put("Content-Type", "application/json");
DslPart body = new PactDslJsonBody()
.stringValue("programCode", "ELA_NGL_G7_TX")
.eachLike("contentResources")
.integerType("tocPosition", 0)
.stringType("contentIdentifier", "l_9d23cb4f-69dc-4032-bb53-73501234dc14_e5f25016-e2fa-4223-8969-2004c644917d")
.closeArray();
return builder
.given("get TOC Summary")
.uponReceiving("get TOC Summary")
.path(getRecommendations)
.method("GET")
.headers(headers)
.willRespondWith()
.status(200)
.body(body)
.toPact();
}
非常感谢。
对您的问题的简短回答是,没有一种方法可以完全按照您的要求进行操作。
常见问题解答中关于为什么不可用的较长答案:
为什么不支持指定可选属性?
首先,假设您在进行验证测试时可以控制提供者的数据(和消费者的数据)。如果你不这样做,那么 Pact 可能是 not the best tool for your situation.
其次,如果 Pact 支持断言元素 $.body.name
可能出现在响应中,那么您编写的消费者代码可以处理可选的 $.body.name
,但实际上,提供者给出$.body.firstname
,没有任何测试会告诉您您做出了错误的假设。请记住,提供者可以 return 额外数据而不会使合同失败,但它必须至少提供您期望的数据。
指定"SOME_VALUE or null"也是如此。如果您的所有提供商验证测试数据 return 都为该密钥设置了空值,您可能认为您已经验证了 "SOME_VALUE",但实际上,您从未验证过。您可能会在生产环境中为该密钥获得完全不同的 "SOME_VALUE",这可能会导致问题。
指定长度为 0 或更大的数组也是如此。如果您的所有提供者验证数据 returned 为 0 长度数组,则您所有的验证测试都将通过,而无需您验证数组的内容。这就是为什么您只能指定最小长度为 1 的数组或零长度数组的原因。
请记住,与描述文档所有可能状态的模式不同,Pact 是 "contract by examples"。如果您需要断言多种变体是可能的,那么您需要为每个变体提供一个示例。但是,在为每个变体添加 Pact 测试之前,请考虑它是否 真的 对您很重要。请记住,每次交互都伴随着 "cost" 的维护和执行时间,您需要考虑在您的特定情况下是否值得付出代价。您最好处理契约中的常见情况,然后编写您的消费者代码以优雅地处理意外变化(例如,通过忽略该数据并发出警报)。
https://docs.pact.io/faq#why-is-there-no-support-for-specifying-optional-attributes
因此 Beth 的回答的 TL;DR:
- 决定什么是有价值的测试 - 空数组、非空数组或两者
- 使用提供者状态指定响应的任何变化(消费者测试)
- 实现提供者测试的状态,以便能够控制响应
我正在使用 PACT 和 Java 进行合同测试,我的问题是我有一个 api 项目可能会像这样出现:
[
{
"programCode": "ELA_NGL_G7_TX",
"contentResources": [
{
"tocPosition": 1827,
"contentIdentifier": "l_6bf0783e-8499-4f6c-9f9b-c8fbdc8dcf6b_e5f25016-e2fa-4223-8969-2004c644917d"
},
{
"tocPosition": 1828,
"contentIdentifier": "l_192af774-54b9-4280-87e9-71f2b86a7d4d_e5f25016-e2fa-4223-8969-2004c644917d",
"skills": [
{
"skillId": "ae836bd9-4758-4665-b3f8-8339313363e3",
"spineId": "63c2b7d0-cd69-4e8a-9761-c90623104b8c"
}
]
}
]
正如您所见,有时内部技能数组会出现,而其他则不会出现,并且不确定如何将此场景纳入我的消费者测试。我的意思是,如果响应有或没有技能数组取决于特定的参数,我可以进行两个不同的测试,这可能没问题,但这里它们来自同一个调用。所以我想我需要的是类似 if else 的东西,如果存在 skills 数组,那么我会断言它的内部子项,否则就忽略它。
这是我的消费者:
@ExtendWith(PactConsumerTestExt.class)
public class PublishContractWithTocGetSummaryTest {
Map<String, String> headers = new HashMap<>();
String getRecommendations = "/toc/getsummary/ELA_NGL_G7_TX";
@Pact(provider = "CRS-METADATA-FILTERING-SERVICE", consumer = "CRS-TOC-RECOMMENDER")
public RequestResponsePact createPact(PactDslWithProvider builder) throws IOException {
headers.put("Content-Type", "application/json");
DslPart body = new PactDslJsonBody()
.stringValue("programCode", "ELA_NGL_G7_TX")
.eachLike("contentResources")
.integerType("tocPosition", 0)
.stringType("contentIdentifier", "l_9d23cb4f-69dc-4032-bb53-73501234dc14_e5f25016-e2fa-4223-8969-2004c644917d")
.closeArray();
return builder
.given("get TOC Summary")
.uponReceiving("get TOC Summary")
.path(getRecommendations)
.method("GET")
.headers(headers)
.willRespondWith()
.status(200)
.body(body)
.toPact();
}
非常感谢。
对您的问题的简短回答是,没有一种方法可以完全按照您的要求进行操作。
常见问题解答中关于为什么不可用的较长答案:
为什么不支持指定可选属性?
首先,假设您在进行验证测试时可以控制提供者的数据(和消费者的数据)。如果你不这样做,那么 Pact 可能是 not the best tool for your situation.
其次,如果 Pact 支持断言元素 $.body.name
可能出现在响应中,那么您编写的消费者代码可以处理可选的 $.body.name
,但实际上,提供者给出$.body.firstname
,没有任何测试会告诉您您做出了错误的假设。请记住,提供者可以 return 额外数据而不会使合同失败,但它必须至少提供您期望的数据。
指定"SOME_VALUE or null"也是如此。如果您的所有提供商验证测试数据 return 都为该密钥设置了空值,您可能认为您已经验证了 "SOME_VALUE",但实际上,您从未验证过。您可能会在生产环境中为该密钥获得完全不同的 "SOME_VALUE",这可能会导致问题。
指定长度为 0 或更大的数组也是如此。如果您的所有提供者验证数据 returned 为 0 长度数组,则您所有的验证测试都将通过,而无需您验证数组的内容。这就是为什么您只能指定最小长度为 1 的数组或零长度数组的原因。
请记住,与描述文档所有可能状态的模式不同,Pact 是 "contract by examples"。如果您需要断言多种变体是可能的,那么您需要为每个变体提供一个示例。但是,在为每个变体添加 Pact 测试之前,请考虑它是否 真的 对您很重要。请记住,每次交互都伴随着 "cost" 的维护和执行时间,您需要考虑在您的特定情况下是否值得付出代价。您最好处理契约中的常见情况,然后编写您的消费者代码以优雅地处理意外变化(例如,通过忽略该数据并发出警报)。
https://docs.pact.io/faq#why-is-there-no-support-for-specifying-optional-attributes
因此 Beth 的回答的 TL;DR:
- 决定什么是有价值的测试 - 空数组、非空数组或两者
- 使用提供者状态指定响应的任何变化(消费者测试)
- 实现提供者测试的状态,以便能够控制响应