如何让jOOQ在单元测试时使用测试表?

How to make jOOQ use test tables during unit tests?

我正在努力弄清楚如何对我的持久性级别方法进行单元测试。对于生产,我使用 postgres,我让 jOOQ 从我的数据库模式生成 Java classes。为了进行测试,我已经配置了一个内存中的 HSQLDB,并为 spring 包含了一个 schema.sql 文件,以创建一个 table 与生产数据库中的完全匹配的文件,每个配置都在一个单独的 application.yaml 文件在 src 或 test.

现在问题来了。我的持久层有方法,直接引用 jOOQ 生成的 table class,显然是因为只有 class 具有与各个列对应的成员字段。一个例子:

private Data DATA = Tables.DATA;

public Timestamp findLatestNonRealtimeClose(String ticker) {
    return (Timestamp) jooq
            .select(max(DATA.DATE))
            .from(DATA)
            .where(DATA.TICKER.eq(ticker))
            .and(DATA.REALTIMECLOSE.eq(Boolean.FALSE))
            .fetch()
            .getValue(0, 0);
}

该方法只是 returns 给定股票代码的最新现有日期条目。在编写测试时,此方法仍将转到真正的生产数据库,而不是测试数据库。我不能只将 table 作为存在于 jOOQ 中的多态参数类型 Table 传递,因为我必须将其转换为 Tables.DATA 才能访问列。如果我想使用测试数据库,我什至不知道将它转换成什么类型​​,因为 HSQLDB table 没有 运行time Java 表示,甚至如果我这样做了,该方法不知道它是否 运行 作为测试的一部分。如何重写方法以考虑测试或生产 运行?

在 Lukas Eder 的 an article 中,据说你不应该对你的数据库代码进行单元测试,但我仍然想这样做。

您可以模拟整个调用链...

when(jooq.select()).thenReturn(whereMock); 
when(whereMock.from(DATA)).thenReturn(fromMock);

等等;然后验证是否正确调用了所有内容。

为您的测试环境替换您的 jOOQ Configuration

我不确定您为什么认为 jOOQ table 引用是这里的问题所在。您应该能够 运行 对任何类型的数据库进行完全相同的 jOOQ 查询而不需要太多努力。唯一的区别应该是配置 jooq 实例的方式(即 DSLContext 及其 Configuration):

  • 生产:使用现有实例
  • 测试:替换为连接HSQLDB的实例,使用SQLDialect.HSQLDB

单元测试与集成测试

In an article authored by Lukas Eder, it is said that you are not supposed to unit test your DB code, but I still would like to do it.

您误解了我所说的 "unit testing",以及我所说的 "integration testing"(这正是您所做的)。我认为后者非常好。当然,我总是建议针对生产数据库产品(即 PostgreSQL,例如 Docker)对您的应用程序进行集成测试,但如果有充分的理由不这样做,也许 HSQLDB 就足够了。

单元测试将(根据我的定义)用任何级别的模拟替换数据库,包括:

我文章中的批评表明,在某些时候,模拟数据库等同于实现数据库,那么为什么不直接使用 off-the-shelf 数据库进行集成测试呢。