【问题标题】:H2 postgresql mode seems not working for meH2 postgresql 模式似乎对我不起作用
【发布时间】:2014-08-05 02:15:26
【问题描述】:

我的应用程序访问 Postgres 数据库,并且我有许多针对 Postgres 的预定义查询(等级、分区、复杂连接等)。现在我想用小测试数据对这些查询行为进行单元测试。所以我从 H2/JUnit 开始。我发现大多数 Postgres 查询,如 Rank、Partition、Complex case when update 等。所以我想到使用 H2 PosgreSQL 兼容模式,认为所有 Postgres 查询都可以在 H2 上工作,如果我错了,请纠正我。

我按照 H2 文档说:

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

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

Function "RANK' not found; in SQL statement

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

【问题讨论】:

  • 您可能会发现阅读 cmets 到类似问题 here 会很有趣。对于它的价值,我支持那些主张如果您的应用程序实际上使用 PostgreSQL,那么您也应该简单地使用 PostgreSQL 进行测试。
  • 嗨@Gord我希望我可以使用Posgres,但作为单元测试的一部分,我应该在像H2这样的内存数据库中使用。作为集成测试的一部分,我可以使用 Postgres。
  • 使用数据库时,它不是单元测试...

标签: java postgresql jdbc h2


【解决方案1】:

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

恐怕这不是真的。

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

您唯一的选择是:

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

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

基于 cmets 的更新:

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

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

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

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

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

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

另见:

至于:

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

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

【讨论】:

  • 嗨@Craig 感谢您的回复。我不能停止使用像 rank() 这样的窗口函数,所以你的意思是我不能在 postgres 兼容模式下使用 H2 来进行排名。我迷失了大部分内存数据库不支持窗口函数。
  • 好吧,如果它对你的项目真的那么重要,你可以在 H2 中实现窗口函数。这不会很容易或很快。我个人建议只在 Pg 上进行测试。我不清楚为什么你不能用你的单元测试来做到这一点。当然,这很不方便,但总比不测试你要运行的东西要好。
  • 即使我同意你的观点,但人们说我不应该在像 Postgres 这样的真实数据库上进行单元测试,我应该在像 H2 这样的内存数据库中使用这些东西。如果我使用像 Postgres 这样的真实数据库,那将是集成测试而不是单元测试。我是数据库测试的新手,所以有点迷茫。
  • “人们说”?参考/链接?对我来说听起来像是 BS。对于一件事,“单元”和“集成”测试之间没有硬性界限。另一方面,H2 也是一个外部组件。纯粹的单元测试将有一个虚拟响应者作为测试工具的一部分。
  • 非常感谢克雷格。我同意你的看法。我的应用程序与 Sybase IQ、DB2、Postgres、ParAccel 等许多数据库通信。我有不同形式的相同逻辑查询来支持所有这些目标。那么你建议我应该使用 Postgres 作为单元测试目标吗?如果所有带有预期最终数据集的查询在 Postgress 中都可以正常工作,我可以假设它在所有其他数据库中都可以正常工作,并且它可以像我对它们进行手动测试一样工作。请指导。您的指导会很有帮助。
猜你喜欢
  • 2018-10-28
  • 1970-01-01
  • 1970-01-01
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-13
相关资源
最近更新 更多