如何测试包含 java.time.Instant 字段的 spring-cloud-contract
How can I test a spring-cloud-contract containing a java.time.Instant field
我想测试一个字段类型为 java.time.Instant 的合同。但并非 Instant 的所有实例都像我预期的那样由 spring-cloud-contract 处理。给定以下简单合约:
Contract.make {
description("Get a version")
request {
method 'GET'
url '/config/version'
headers {
contentType(applicationJson())
}
}
response {
status 200
body(
nr: 42,
creationDate: producer(anyIso8601WithOffset())
)
headers {
contentType(applicationJson())
}
}
}
以及此服务实现:
@RestController
public class VersionController {
@GetMapping(path = "/version")
public ResponseEntity<Version> getCurrentVersion() {
return ResponseEntity.ok(new Version(42, Instant.ofEpochMilli(0)));
}
}
执行 gradle 测试工作正常。但是,如果我用 Instant.now() 替换 Instant,我的提供商测试将失败并显示
java.lang.IllegalStateException: Parsed JSON [{"nr":42,"creationDate":"2018-11-11T15:28:26.958284Z"}] doesn't match the JSON path [$[?(@.['creationDate'] =~ /([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.\d{3})?(Z|[+-][01]\d:[0-5]\d)/)]]
这是可以理解的,因为 Instant.now() 生成的 Instant 其字符串表示确实与 anyIso8601WithOffset()
模式不匹配。但这是为什么呢?为什么 Instants 以不同的方式表示,我如何描述一个在任何时刻都有效的合约?
好的,我找到了适合我的解决方案。虽然我不知道这是不是要走的路。
为了始终获得与序列化即时完全相同的格式,我将我的版本 bean 相应 属性 的格式定义如下:
public class Version {
private final int nr;
private final Instant creationDate;
@JsonCreator
public Version(
@JsonProperty("nr") int nr,
@JsonProperty("creationDate") Instant creationDate)
{
this.nr = nr;
this.creationDate = creationDate;
}
public int getNr() {
return nr;
}
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX", timezone = "UTC")
public Instant getCreationDate() {
return creationDate;
}
}
我想测试一个字段类型为 java.time.Instant 的合同。但并非 Instant 的所有实例都像我预期的那样由 spring-cloud-contract 处理。给定以下简单合约:
Contract.make {
description("Get a version")
request {
method 'GET'
url '/config/version'
headers {
contentType(applicationJson())
}
}
response {
status 200
body(
nr: 42,
creationDate: producer(anyIso8601WithOffset())
)
headers {
contentType(applicationJson())
}
}
}
以及此服务实现:
@RestController
public class VersionController {
@GetMapping(path = "/version")
public ResponseEntity<Version> getCurrentVersion() {
return ResponseEntity.ok(new Version(42, Instant.ofEpochMilli(0)));
}
}
执行 gradle 测试工作正常。但是,如果我用 Instant.now() 替换 Instant,我的提供商测试将失败并显示
java.lang.IllegalStateException: Parsed JSON [{"nr":42,"creationDate":"2018-11-11T15:28:26.958284Z"}] doesn't match the JSON path [$[?(@.['creationDate'] =~ /([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.\d{3})?(Z|[+-][01]\d:[0-5]\d)/)]]
这是可以理解的,因为 Instant.now() 生成的 Instant 其字符串表示确实与 anyIso8601WithOffset()
模式不匹配。但这是为什么呢?为什么 Instants 以不同的方式表示,我如何描述一个在任何时刻都有效的合约?
好的,我找到了适合我的解决方案。虽然我不知道这是不是要走的路。
为了始终获得与序列化即时完全相同的格式,我将我的版本 bean 相应 属性 的格式定义如下:
public class Version {
private final int nr;
private final Instant creationDate;
@JsonCreator
public Version(
@JsonProperty("nr") int nr,
@JsonProperty("creationDate") Instant creationDate)
{
this.nr = nr;
this.creationDate = creationDate;
}
public int getNr() {
return nr;
}
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX", timezone = "UTC")
public Instant getCreationDate() {
return creationDate;
}
}