无法测试 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() | ...

真的就是这么简单