H2 postgresql模式似乎不适合我

2022-09-01 17:03:47

我的应用程序访问Postgres数据库,我有许多预定义的查询(Rank,Partition,复杂联接等),我针对Postgres触发。现在我想用小的测试数据对这些查询行为进行单元测试。

所以我从H2 / JUnit开始。我发现大多数Postgres查询,如排名,分区,更新时的复杂情况等。所以我想到使用H2 PosgreSQL兼容模式 - 所有Postgres查询都可以在H2上运行吗?

我按照H2文档说:

要使用 PostgreSQL 模式,请使用数据库 URL jdbc:h2:~/test;MODE=PostgreSQL 或 SQL 语句 SET MODE PostgreSQL.

我启用了模式使用,我试图触发其中一个查询,它涉及并在Postgres中工作,但它不起作用H2。它给了我以下例外:SET MODE PostgreSQLrank()

Function "RANK' not found; in SQL statement

我是H2和数据库测试的新手。我正在使用H2 JDBC驱动程序来触发Postgres查询,因为我认为H2 Posgress兼容模式将允许我触发Postgres查询。


答案 1

所以我想使用H2 PosgreSQL兼容模式,认为所有postgres查询都可以在H2上工作,如果我错了,请纠正我

恐怕这不是真的。

H2尝试模拟PostgreSQL语法并支持一些功能和扩展。它永远不会完全匹配PostgreSQL的行为,并且不支持所有功能。

您拥有的唯一选项是:

  • 在测试中使用PostgreSQL;或
  • 停止使用 H2 不支持的功能

我建议使用Pg进行测试。编写一个测试工具相对简单,该工具是 initdb 的 postgres 实例,然后启动它进行测试,然后在之后将其拆除。

根据评论进行更新:

在“单元”和“集成”测试之间没有强硬的界限。在这种情况下,H2也是一个外部元件。纯粹的单元测试将有一个虚拟的查询响应者作为测试工具的一部分。针对 H2 的测试与针对 PostgreSQL 的测试一样,都是一种“集成”测试。它是进程内和内存中的事实是一种方便,但在功能上并不重要。

如果你想进行单元测试,你应该为你的应用程序编写另一个数据库目标,与你的“PostgreSQL”,“SybaseIQ”等目标一起。称它为“MockDatabase”。这应该只返回查询的预期结果。它并不真正运行查询,它的存在只是为了测试其余代码的行为。

就个人而言,我认为这是对时间的巨大浪费,但这就是单元测试纯粹主义者为了避免将外部依赖项引入测试工具而做的事情。

如果您坚持对数据库组件进行单元(而不是集成)测试,但不能/不会编写模拟接口,则必须找到一种方法来使用现有接口。H2将是一个合理的候选者 - 但是你必须编写一个新的后端,其中包含一组适用于H2的新查询,你不能只是重用你的PostgreSQL后端。正如我们已经建立的那样,H2不支持您需要与PostgreSQL一起使用的所有功能,因此您必须找到不同的方法来使用H2执行相同的操作。一种选择是创建一个简单的H2数据库,其中包含“预期”结果和返回这些结果的简单查询,完全忽略实际应用程序的架构。这里唯一真正的缺点是,维护它可能是一个主要的痛苦...但那是单元测试。

就个人而言,我只是用PostgreSQL进行测试。除非我正在测试作为窄接口明确定义的单元的独立单个类或模块,否则我不在乎有人称它为“单元”还是“集成”测试。我将对数据验证类进行单元测试。对于数据库接口代码,纯粹的单元测试几乎没有意义,我只做集成测试。

虽然拥有进程内内存数据库很方便,但这不是必需的。您可以编写测试工具,以便设置代码成为新的PostgreSQL并启动它;然后拆解代码会杀死邮局主管并删除数据目录。我在这个答案中写了更多关于这一点的内容initdb

另请参阅:

至于:

如果具有预期最终数据集的所有查询在Postgress中工作正常,我可以假设它在所有其他数据库中都可以正常工作

如果我正确地理解了你所说的,那么是的,就是这样 - 如果你的代码的其余部分与PostgreSQL中的数据集一起工作,那么它通常应该与包含来自另一个数据库的相同数据的数据集相同。当然,只要它使用简单的数据类型而不是数据库特定的功能。


答案 2

推荐