Spring Cloud Contract LocalDateTime 断言失败
Spring Cloud Contract LocalDateTime assertions fail
最后一天,我一直在努力处理 Spring 合同测试中的 LocalDateTime。
基础class:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public abstract class VennotenDossiersConsumerBase {
@Autowired
private OptInController optInController;
@Autowired
private ActieLogController actieLogController;
@MockBean
private OptInService optInService;
@MockBean
private ActieLogService actieLogService;
@BeforeEach
public void setup() throws IOException {
String liantisId = "liantisId";
String applicatieNaam = "applicatieNaam";
String gebruikerId = "gebruikerId";
String optInGebruikerId = "optInGebruikerId";
StandaloneMockMvcBuilder standaloneMockMvcBuilder
= MockMvcBuilders.standaloneSetup(optInController, actieLogController);
RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
OptIn createOptIn = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/registerOptInRequestBody.json"), OptIn.class);
OptIn getOptIn = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getOptInResponseBody.json"), OptIn.class);
List<OptIn> getOptInByLiantisId = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getOptInByLiantisIdResponseBody.json"), new TypeReference<List<OptIn>>() {});
List<OptIn> getAllOptIns = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getAllOptInsResponseBody.json"), new TypeReference<List<OptIn>>() {});
List<ActieLog> getAllActionLogs = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getAllActionLogsResponseBody.json"), new TypeReference<List<ActieLog>>() {});
List<ActieLog> getActionLogsByLiantisId = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getActionLogsByLiantisIdResponseBody.json"), new TypeReference<List<ActieLog>>() {});
List<ActieLog> getActionLogsByGebruikerId = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getActionLogsByGebruikerIdResponseBody.json"), new TypeReference<List<ActieLog>>() {});
when(optInService.createOptIn(any(OptIn.class))).thenReturn(createOptIn);
when(optInService.getOptIn(liantisId, applicatieNaam, optInGebruikerId)).thenReturn(getOptIn);
when(optInService.getAllOptIns()).thenReturn(getAllOptIns);
when(optInService.getOptInsByLiantisId(liantisId)).thenReturn(getOptInByLiantisId);
when(actieLogService.getAllActionLogs()).thenReturn(getAllActionLogs);
when(actieLogService.getActionLogsByLiantisId(liantisId)).thenReturn(getActionLogsByLiantisId);
when(actieLogService.getActionLogsByGebruikerId(gebruikerId)).thenReturn(getActionLogsByGebruikerId);
}
}
groovy 脚本:
Contract.make {
description "should return an Action Log for GebruikerId"
request{
url("api/actionlogs") {
headers {
contentType(applicationJson())
}
queryParameters {
parameter("gebruikerId","gebruikerId")
}
method GET()
}
}
response {
status OK()
headers {
contentType(applicationJson())
}
body(file("getActionLogsByGebruikerIdResponseBody.json"))
}
}
ResponseBody.json:
[
{
"liantisId": "liantisId1",
"entiteitActie": "prospect",
"applicatieNaam": "applicatieNaam1",
"actie": "CREATE",
"optInGebruiker": {
"gebruikerId": "gebruikerId",
"username": "username1",
"qualificatie": "qualificatie1"
},
"actionLoggedDate": "2020-03-02T09:54:10.758"
}
]
生成的测试:
public class VennotenDossiersConsumerTest extends VennotenDossiersConsumerBase {
@Test
public void validate_getActionLogsByGebruikerId() throws Exception {
// given:
MockMvcRequestSpecification request = given()
.header("Content-Type", "application/json");
// when:
ResponseOptions response = given().spec(request)
.queryParam("gebruikerId","gebruikerId")
.get("api/actionlogs");
// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).matches("application/json.*");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).array().contains("['liantisId']").isEqualTo("liantisId1");
assertThatJson(parsedJson).array().contains("['entiteitActie']").isEqualTo("prospect");
assertThatJson(parsedJson).array().contains("['applicatieNaam']").isEqualTo("applicatieNaam1");
assertThatJson(parsedJson).array().contains("['actie']").isEqualTo("CREATE");
assertThatJson(parsedJson).array().field("['optInGebruiker']").field("['gebruikerId']").isEqualTo("gebruikerId");
assertThatJson(parsedJson).array().field("['optInGebruiker']").field("['username']").isEqualTo("username1");
assertThatJson(parsedJson).array().field("['optInGebruiker']").field("['qualificatie']").isEqualTo("qualificatie1");
assertThatJson(parsedJson).array().contains("['actionLoggedDate']").isEqualTo("2020-03-02T09:54:10.758");
}
我在 运行 测试时得到的错误:
java.lang.IllegalStateException: Parsed JSON [[{"liantisId":"liantisId","entiteitActie":"prospect","applicatieNaam":"applicatieNaam1","actie":"CREATE","optInGebruiker":{"gebruikerId":"gebruikerId1","username":"username1","qualificatie":"qualificatie1"},"actionLoggedDate":[2020,3,2,9,54,10,758000000]}]] doesn't match the JSON path [$[*][?(@.['actionLoggedDate'] == '2020-03-02T09:54:10.758')]]
at com.toomuchcoding.jsonassert.JsonAsserter.check(JsonAsserter.java:228)
at com.toomuchcoding.jsonassert.JsonAsserter.checkBufferedJsonPathString(JsonAsserter.java:267)
at com.toomuchcoding.jsonassert.JsonAsserter.isEqualTo(JsonAsserter.java:101)
at be.liantis.gdpr.service.contracts.VennotenDossiersConsumerTest.validate_getActionLogsByLiantisId(VennotenDossiersConsumerTest.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:532)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod(TestMethodTestDescriptor.java:171)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:167)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:114)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:59)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:108)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:188)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
因此在生成的测试中执行get请求时,它returns localDateTime作为一个数组。
我一直在尝试将自定义 ObjectMappers 分配给 RestAssuredMockMVC,但没有任何效果。
如果我使用
RestAssuredMockMvc.config().objectMapperConfig(ObjectMapperConfig.objectMapperConfig().jackson2ObjectMapperFactory((type, s) -> OBJECT_MAPPER));
没用。
如果我将它作为参数传递给 standaloneSetup() 也不起作用。
我也试过 mockMVC 消息转换器,也没用。
以前有人遇到过这个问题吗?
我找不到任何使用 LOCALDATE 或 LOCALDATETIME 的 Spring 合同示例。
不包含 localDateTime 的测试成功,没有任何问题。
有人知道该怎么做吗?
我自己解决了这个问题,我已经停止使用独立设置。
我为 RestAssured 提供了我的 webappcontext,然后它使用了正确的对象映射器。
RestAssuredMockMvc.webAppContextSetup(appContext)
appContext 是我的 Autowired WebApplicationContext:
@Autowired
private WebApplicationContext appContext;
为了绕过我因为安全上下文而得到的 401,我在基础上使用了 @WithMockUser class。
@WithMockUser
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public abstract class VennotenDossiersConsumerBase
最后一天,我一直在努力处理 Spring 合同测试中的 LocalDateTime。
基础class:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public abstract class VennotenDossiersConsumerBase {
@Autowired
private OptInController optInController;
@Autowired
private ActieLogController actieLogController;
@MockBean
private OptInService optInService;
@MockBean
private ActieLogService actieLogService;
@BeforeEach
public void setup() throws IOException {
String liantisId = "liantisId";
String applicatieNaam = "applicatieNaam";
String gebruikerId = "gebruikerId";
String optInGebruikerId = "optInGebruikerId";
StandaloneMockMvcBuilder standaloneMockMvcBuilder
= MockMvcBuilders.standaloneSetup(optInController, actieLogController);
RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
OptIn createOptIn = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/registerOptInRequestBody.json"), OptIn.class);
OptIn getOptIn = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getOptInResponseBody.json"), OptIn.class);
List<OptIn> getOptInByLiantisId = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getOptInByLiantisIdResponseBody.json"), new TypeReference<List<OptIn>>() {});
List<OptIn> getAllOptIns = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getAllOptInsResponseBody.json"), new TypeReference<List<OptIn>>() {});
List<ActieLog> getAllActionLogs = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getAllActionLogsResponseBody.json"), new TypeReference<List<ActieLog>>() {});
List<ActieLog> getActionLogsByLiantisId = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getActionLogsByLiantisIdResponseBody.json"), new TypeReference<List<ActieLog>>() {});
List<ActieLog> getActionLogsByGebruikerId = objectMapper.readValue(new File("src/test/resources/contracts/vennotenDossiersConsumer/getActionLogsByGebruikerIdResponseBody.json"), new TypeReference<List<ActieLog>>() {});
when(optInService.createOptIn(any(OptIn.class))).thenReturn(createOptIn);
when(optInService.getOptIn(liantisId, applicatieNaam, optInGebruikerId)).thenReturn(getOptIn);
when(optInService.getAllOptIns()).thenReturn(getAllOptIns);
when(optInService.getOptInsByLiantisId(liantisId)).thenReturn(getOptInByLiantisId);
when(actieLogService.getAllActionLogs()).thenReturn(getAllActionLogs);
when(actieLogService.getActionLogsByLiantisId(liantisId)).thenReturn(getActionLogsByLiantisId);
when(actieLogService.getActionLogsByGebruikerId(gebruikerId)).thenReturn(getActionLogsByGebruikerId);
}
}
groovy 脚本:
Contract.make {
description "should return an Action Log for GebruikerId"
request{
url("api/actionlogs") {
headers {
contentType(applicationJson())
}
queryParameters {
parameter("gebruikerId","gebruikerId")
}
method GET()
}
}
response {
status OK()
headers {
contentType(applicationJson())
}
body(file("getActionLogsByGebruikerIdResponseBody.json"))
}
}
ResponseBody.json:
[
{
"liantisId": "liantisId1",
"entiteitActie": "prospect",
"applicatieNaam": "applicatieNaam1",
"actie": "CREATE",
"optInGebruiker": {
"gebruikerId": "gebruikerId",
"username": "username1",
"qualificatie": "qualificatie1"
},
"actionLoggedDate": "2020-03-02T09:54:10.758"
}
]
生成的测试:
public class VennotenDossiersConsumerTest extends VennotenDossiersConsumerBase {
@Test
public void validate_getActionLogsByGebruikerId() throws Exception {
// given:
MockMvcRequestSpecification request = given()
.header("Content-Type", "application/json");
// when:
ResponseOptions response = given().spec(request)
.queryParam("gebruikerId","gebruikerId")
.get("api/actionlogs");
// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).matches("application/json.*");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).array().contains("['liantisId']").isEqualTo("liantisId1");
assertThatJson(parsedJson).array().contains("['entiteitActie']").isEqualTo("prospect");
assertThatJson(parsedJson).array().contains("['applicatieNaam']").isEqualTo("applicatieNaam1");
assertThatJson(parsedJson).array().contains("['actie']").isEqualTo("CREATE");
assertThatJson(parsedJson).array().field("['optInGebruiker']").field("['gebruikerId']").isEqualTo("gebruikerId");
assertThatJson(parsedJson).array().field("['optInGebruiker']").field("['username']").isEqualTo("username1");
assertThatJson(parsedJson).array().field("['optInGebruiker']").field("['qualificatie']").isEqualTo("qualificatie1");
assertThatJson(parsedJson).array().contains("['actionLoggedDate']").isEqualTo("2020-03-02T09:54:10.758");
}
我在 运行 测试时得到的错误:
java.lang.IllegalStateException: Parsed JSON [[{"liantisId":"liantisId","entiteitActie":"prospect","applicatieNaam":"applicatieNaam1","actie":"CREATE","optInGebruiker":{"gebruikerId":"gebruikerId1","username":"username1","qualificatie":"qualificatie1"},"actionLoggedDate":[2020,3,2,9,54,10,758000000]}]] doesn't match the JSON path [$[*][?(@.['actionLoggedDate'] == '2020-03-02T09:54:10.758')]]
at com.toomuchcoding.jsonassert.JsonAsserter.check(JsonAsserter.java:228)
at com.toomuchcoding.jsonassert.JsonAsserter.checkBufferedJsonPathString(JsonAsserter.java:267)
at com.toomuchcoding.jsonassert.JsonAsserter.isEqualTo(JsonAsserter.java:101)
at be.liantis.gdpr.service.contracts.VennotenDossiersConsumerTest.validate_getActionLogsByLiantisId(VennotenDossiersConsumerTest.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:532)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod(TestMethodTestDescriptor.java:171)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:167)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:114)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:59)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:108)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:188)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
因此在生成的测试中执行get请求时,它returns localDateTime作为一个数组。 我一直在尝试将自定义 ObjectMappers 分配给 RestAssuredMockMVC,但没有任何效果。
如果我使用
RestAssuredMockMvc.config().objectMapperConfig(ObjectMapperConfig.objectMapperConfig().jackson2ObjectMapperFactory((type, s) -> OBJECT_MAPPER));
没用。
如果我将它作为参数传递给 standaloneSetup() 也不起作用。
我也试过 mockMVC 消息转换器,也没用。
以前有人遇到过这个问题吗? 我找不到任何使用 LOCALDATE 或 LOCALDATETIME 的 Spring 合同示例。
不包含 localDateTime 的测试成功,没有任何问题。
有人知道该怎么做吗?
我自己解决了这个问题,我已经停止使用独立设置。
我为 RestAssured 提供了我的 webappcontext,然后它使用了正确的对象映射器。
RestAssuredMockMvc.webAppContextSetup(appContext)
appContext 是我的 Autowired WebApplicationContext:
@Autowired
private WebApplicationContext appContext;
为了绕过我因为安全上下文而得到的 401,我在基础上使用了 @WithMockUser class。
@WithMockUser
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public abstract class VennotenDossiersConsumerBase