我正在努力弄清楚如何对持久性级别方法进行单元测试。为了生产,我使用postgres,我有jOOQ从我的数据库模式生成Java类。为了测试,我已经配置了一个内存中的HSQLDB,并为spring创建了一个schema.sql文件,以创建一个与生产数据库中的表完全匹配的表,每个配置都在src或test中的单独application.yaml文件中。
现在问题就在于此。我的持久层有方法,直接引用由jOOQ生成的表类,显然是因为只有该类具有与各列对应的成员字段。一个例子:
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);
}
该方法只返回给定股票代码的最新现有日期条目。在编写测试时,此方法仍将转到实际生产数据库,而不是测试数据库。我不能将表作为jOOQ中存在的多态参数类型表传递,因为我必须将其转换为Tables.DATA才能访问列。如果我想使用测试数据库,我甚至不知道要将它转换为什么类型,因为HSQLDB表没有运行时Java表示,即使我这样做,该方法也不知道如果它是作为测试的一部分运行。如何重写方法以考虑测试或生产运行?
在Lukas Eder撰写的an article中,据说您不应该对您的数据库代码进行单元测试,但我仍然希望这样做。
答案 0 :(得分:2)
Configuration
我不确定为什么你认为jOOQ表引用是这里的问题。您应该能够毫不费力地针对任何类型的数据库运行完全相同的jOOQ查询。唯一的区别应该是您配置jooq
实例的方式(即DSLContext
及其Configuration
):
SQLDialect.HSQLDB
在Lukas Eder撰写的一篇文章中,据说你不应该对你的数据库代码进行单元测试,但我仍然愿意这样做。
你误解了我所说的"单元测试",以及我所说的"集成测试" (这就是你正在做的事情)。在我看来,后者完全没问题。当然,我总是建议将您的应用程序与生产数据库产品(例如PostgreSQL,例如Docker)集成测试,但如果有充分理由不这样做,那么HSQLDB就足够了。
单元测试(根据我的定义)将数据库替换为任何级别的模拟,包括:
MockConnection
API 我文章的批评表明,在某些时候,模拟数据库等同于实现数据库,所以为什么不使用现成的数据库进行集成测试呢。
答案 1 :(得分:1)
你可以模拟整个调用链......
when(jooq.select()).thenReturn(whereMock);
when(whereMock.from(DATA)).thenReturn(fromMock);
等等;然后验证一切都被正确调用。