无法测试 UUID
unable to test UUID
我有一个 spring boot 2.6.7 应用程序,使用 Liquibase、Gradle 和 Spock。我有一个使用 guid 格式字符串作为 ID 的 class:
@Entity
@Table(name = "devices")
public class Device {
@Id
@NotNull
@Pattern(regexp = "^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$",
message = "Invalid id received")
private String deviceId;
@NotNull
private DeviceType deviceType;
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate manufactureDate;
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate activationDate;
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate deactivationDate;
private Status deviceStatus;
我有几个端点接受这个实体并persist/find/update它。当我查看数据库时,我看到列已正确填充。所以它似乎有效。
这是我的 liquibase table:
- changeSet:
id: 7
preConditions:
- onFail: MARK_RAN
not:
tableExists:
tableName:
devices
changes:
- createTable:
tableName: devices
columns:
nullable: false
- column:
name: device_id
type: varchar(255)
constraints:
primaryKey: true
nullable: false
- column:
name: device_type
type: varchar(255)
constraints:
nullable: true
- column:
name: manufacture_date
type: date
constraints:
nullable: true
- column:
name: activation_date
type: date
constraints:
nullable: true
- column:
name: deactivation_date
type: date
constraints:
nullable: true
- column:
name: internal_id
type: varchar(255)
constraints:
nullable: true
- column:
name: device_status
type: varchar(255)
constraints:
nullable: true
但是,我现在正尝试将我的代码包装在测试中,并且我将 运行 放入无法将字符串转换为 UUID 的问题中。这是测试:
given:
def device = new Device(internalId: internalId, deviceId: deviceId,
deviceType: deviceType, deviceStatus: deviceStatus, role: role, activationDate: activationDate, deactivationDate: deactivationDate, manufactureDate: manufactureDate)
def result = deviceRepository.save(device)
when:
def isValid = deviceServices.validateDevice(result)
then:
isValid == testResult
where:
deviceId | deviceType | deviceStatus | manufactureDate | activationDate | deactivationDate | || testResult
UUID.randomUUID() | DeviceType.EQUIPMENT | Status.ACTIVATED | LocalDate.now() | LocalDate.now() | null || true
这是通过尝试插入 H2 开始测试时的错误。该字段声明为 varchar,但由于某种原因,堆栈跟踪提到了 NumberFormat 和 Long 值。
SQL Error: 22018, SQLState: 22018
2022-05-12 06:24:34.083 ERROR 42198 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Data conversion error converting "faf837fa-8584-4dff-a8d1-bd4d9a8af74c"; SQL statement:
select identity0_.device_id as scanned_1_6_, identity0_.internal_id as internal2_6_ from identities identity0_ where identity0_.device_id=? [22018-212]
...
Caused by: org.h2.message.DbException: Data conversion error converting "9bbb114a-bb99-443c-9106-dd28210c4e7b" [22018-212]
at org.h2.message.DbException.get(DbException.java:212)
at org.h2.value.ValueStringBase.getLong(ValueStringBase.java:142)
at org.h2.value.Value.convertToBigint(Value.java:1645)
at org.h2.value.Value.convertTo(Value.java:1137)
at org.h2.value.Value.convertForAssignTo(Value.java:1092)
at org.h2.table.Column.validateConvertUpdateSequence(Column.java:369)
... 53 more
Caused by: org.h2.jdbc.JdbcSQLDataException: Data conversion error converting "9bbb114a-bb99-443c-9106-dd28210c4e7b" [22018-212]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:506)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:477)
... 59 more
Caused by: java.lang.NumberFormatException: For input string: "9bbb114a-bb99-443c-9106-dd28210c4e7b"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Long.parseLong(Long.java:692)
at java.base/java.lang.Long.parseLong(Long.java:817)
at org.h2.value.ValueStringBase.getLong(ValueStringBase.java:140)
... 57 more
我觉得我没有将主键设为 UUID,或者没有常规 ID 然后将 deviceId 用作 UUID,这让我陷入了困境。但是,这是生产代码,我对通过 Liquibase 更改 table 结构犹豫不决。
有没有办法让 Liquibase 或 Spock 解决这个问题?同样,它在生产中运行良好,我只是无法对其进行集成测试(这可能是 H2 限制?)
更新:
我有另一个具有相同行为的测试 - 无法将 UUID 转换为 class 的字符串属性。如果我将“UUID.randomUUID()”更改为“123”,它会按预期工作。
因为我只在我的测试中看到了这一点,而 SqlExceptionHelper 是个例外,我想知道测试 H2 是否不能处理生产 Postgres 所做的转换?我为 HSQL 更改了 H2 并得到了相同类型的错误。
Device.deviceID
的类型是 String
,但您的 Spock 规范中 deviceId
的类型是 UUID
。所以你要么需要使用
def device = new Device(internalId: internalId, deviceId: deviceId.toString(), ...
或
where:
deviceId | ...
UUID.randomUUID().toString() | ...
真的就是这么简单
我有一个 spring boot 2.6.7 应用程序,使用 Liquibase、Gradle 和 Spock。我有一个使用 guid 格式字符串作为 ID 的 class:
@Entity
@Table(name = "devices")
public class Device {
@Id
@NotNull
@Pattern(regexp = "^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$",
message = "Invalid id received")
private String deviceId;
@NotNull
private DeviceType deviceType;
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate manufactureDate;
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate activationDate;
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate deactivationDate;
private Status deviceStatus;
我有几个端点接受这个实体并persist/find/update它。当我查看数据库时,我看到列已正确填充。所以它似乎有效。
这是我的 liquibase table:
- changeSet:
id: 7
preConditions:
- onFail: MARK_RAN
not:
tableExists:
tableName:
devices
changes:
- createTable:
tableName: devices
columns:
nullable: false
- column:
name: device_id
type: varchar(255)
constraints:
primaryKey: true
nullable: false
- column:
name: device_type
type: varchar(255)
constraints:
nullable: true
- column:
name: manufacture_date
type: date
constraints:
nullable: true
- column:
name: activation_date
type: date
constraints:
nullable: true
- column:
name: deactivation_date
type: date
constraints:
nullable: true
- column:
name: internal_id
type: varchar(255)
constraints:
nullable: true
- column:
name: device_status
type: varchar(255)
constraints:
nullable: true
但是,我现在正尝试将我的代码包装在测试中,并且我将 运行 放入无法将字符串转换为 UUID 的问题中。这是测试:
given:
def device = new Device(internalId: internalId, deviceId: deviceId,
deviceType: deviceType, deviceStatus: deviceStatus, role: role, activationDate: activationDate, deactivationDate: deactivationDate, manufactureDate: manufactureDate)
def result = deviceRepository.save(device)
when:
def isValid = deviceServices.validateDevice(result)
then:
isValid == testResult
where:
deviceId | deviceType | deviceStatus | manufactureDate | activationDate | deactivationDate | || testResult
UUID.randomUUID() | DeviceType.EQUIPMENT | Status.ACTIVATED | LocalDate.now() | LocalDate.now() | null || true
这是通过尝试插入 H2 开始测试时的错误。该字段声明为 varchar,但由于某种原因,堆栈跟踪提到了 NumberFormat 和 Long 值。
SQL Error: 22018, SQLState: 22018
2022-05-12 06:24:34.083 ERROR 42198 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Data conversion error converting "faf837fa-8584-4dff-a8d1-bd4d9a8af74c"; SQL statement:
select identity0_.device_id as scanned_1_6_, identity0_.internal_id as internal2_6_ from identities identity0_ where identity0_.device_id=? [22018-212]
...
Caused by: org.h2.message.DbException: Data conversion error converting "9bbb114a-bb99-443c-9106-dd28210c4e7b" [22018-212]
at org.h2.message.DbException.get(DbException.java:212)
at org.h2.value.ValueStringBase.getLong(ValueStringBase.java:142)
at org.h2.value.Value.convertToBigint(Value.java:1645)
at org.h2.value.Value.convertTo(Value.java:1137)
at org.h2.value.Value.convertForAssignTo(Value.java:1092)
at org.h2.table.Column.validateConvertUpdateSequence(Column.java:369)
... 53 more
Caused by: org.h2.jdbc.JdbcSQLDataException: Data conversion error converting "9bbb114a-bb99-443c-9106-dd28210c4e7b" [22018-212]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:506)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:477)
... 59 more
Caused by: java.lang.NumberFormatException: For input string: "9bbb114a-bb99-443c-9106-dd28210c4e7b"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Long.parseLong(Long.java:692)
at java.base/java.lang.Long.parseLong(Long.java:817)
at org.h2.value.ValueStringBase.getLong(ValueStringBase.java:140)
... 57 more
我觉得我没有将主键设为 UUID,或者没有常规 ID 然后将 deviceId 用作 UUID,这让我陷入了困境。但是,这是生产代码,我对通过 Liquibase 更改 table 结构犹豫不决。
有没有办法让 Liquibase 或 Spock 解决这个问题?同样,它在生产中运行良好,我只是无法对其进行集成测试(这可能是 H2 限制?)
更新: 我有另一个具有相同行为的测试 - 无法将 UUID 转换为 class 的字符串属性。如果我将“UUID.randomUUID()”更改为“123”,它会按预期工作。
因为我只在我的测试中看到了这一点,而 SqlExceptionHelper 是个例外,我想知道测试 H2 是否不能处理生产 Postgres 所做的转换?我为 HSQL 更改了 H2 并得到了相同类型的错误。
Device.deviceID
的类型是 String
,但您的 Spock 规范中 deviceId
的类型是 UUID
。所以你要么需要使用
def device = new Device(internalId: internalId, deviceId: deviceId.toString(), ...
或
where:
deviceId | ...
UUID.randomUUID().toString() | ...
真的就是这么简单