33

我有一个应用程序,其中许多“单元”测试在执行期间使用与 Oracle 数据库的真实连接。

可以想象,执行这些测试需要花费太多时间,因为它们需要初始化一些 Spring 上下文,并与 Oracle 实例通信。除此之外,我们必须管理复杂的机制,例如事务,以避免在测试执行后修改数据库(即使我们使用类似 Spring 的有用类AbstractAnnotationAwareTransactionalTests)。

所以我的想法是用内存数据库逐步替换这个 Oracle 测试实例。我会使用hsqldb或者更好h2

我的问题是知道什么是最好的方法来做到这一点。我主要关心的是内存数据库结构的构建和参考数据的插入。

当然,我可以从 Oracle 中提取数据库结构,使用SQL Developeror之类的工具TOAD,然后修改这些脚本以使其适应hsqldborh2语言。但我认为这不是更好的方法。


事实上,我已经在另一个项目中使用hsqldb.,但我已经手动编写了所有脚本来创建表。幸运的是,我只需要创建几张表。在此步骤中,我的主要问题是将用于创建表的 Oracle 脚本“翻译”成该hsqldb语言。

例如,使用以下 sql 命令在 Oracle 中创建的表:

CREATE TABLE FOOBAR (
    SOME_ID NUMBER,
    SOME_DATE DATE, -- Add primary key constraint
    SOME_STATUS NUMBER,
    SOME_FLAG NUMBER(1) DEFAULT 0 NOT NULL);

需要“翻译”为hsqldb

CREATE TABLE FOOBAR (
    SOME_ID NUMERIC,
    SOME_DATE TIMESTAMP PRIMARY KEY,
    SOME_STATUS NUMERIC,
    SOME_FLAG INTEGER DEFAULT 0 NOT NULL);

在我当前的项目中,有太多表无法手动执行...


所以我的问题:

  • 你可以给我什么建议来实现这一目标?
  • 是否提供h2hsqldb提供一些工具来从 Oracle 连接生成脚本?

技术信息

Java 1.6、Spring 2.5、Oracle 10.g、Maven 2


编辑

关于我的单元测试的一些信息:

在我使用的应用程序中hsqldb,我进行了以下测试: - 一些与 DB 无关的“基本”单元测试。- 对于 DAO 测试,我曾经hsqldb执行数据库操作,例如 CRUD。- 然后,在服务层,我曾经Mockito模拟我的 DAO 对象,以便专注于服务测试而不是整个应用程序(即服务 + dao + DB)。

在我当前的应用程序中,我们遇到了最糟糕的情况:DAO 层测试需要运行 Oracle 连接。服务层不使用(还)任何模拟对象来模拟 DAO。因此服务测试需要 Oracle 连接。

我知道模拟和内存数据库是两个不同的点,我会尽快解决它们。但是,我的第一步是尝试通过内存数据库删除 Oracle 连接,然后我将利用我的Mockito知识来增强测试。

请注意,我还想将单元测试与集成测试分开。后者需要访问 Oracle 数据库,才能执行“真正的”测试,但我主要担心(这就是这个问题的目的)是我今天几乎所有的单元测试都不是孤立运行的。

4

4 回答 4

19

使用内存/Java 数据库进行测试。与您尝试在测试中“抽象”数据库相比,这将确保测试更接近真实世界。可能这样的测试也更容易编写和维护。另一方面,您可能确实想在测试中“抽象”出 UI,因为 UI 测试通常很难自动化。

您发布的 Oracle 语法适用于 H2 数据库(我刚刚对其进行了测试),因此 H2 似乎比 HSQLDB 更好地支持 Oracle 语法。免责声明:我是 H2 的作者之一。如果某些东西不起作用,请将其发布在 H2 邮件列表中。

无论如何,您应该在版本控制系统中拥有数据库的 DDL 语句。您也可以使用这些脚本进行测试。可能您还需要支持多个模式版本 - 在这种情况下,您可以编写版本更新脚本(更改表...)。使用 Java 数据库,您也可以测试它们。

顺便说一句,在使用 H2 或 HSQLDB 时,您不一定需要使用内存模式。即使您保留数据,这两个数据库也很快。而且它们很容易安装(只是一个 jar 文件)并且需要的内存比 Oracle 少得多。

于 2010-09-24T07:51:46.557 回答
6

最新的 HSQLDB 2.0.1 通过语法兼容性标志 sql.syntax_ora=true 支持 DUAL、ROWNUM、NEXTVAL 和 CURRVAL 的 ORACLE 语法。以同样的方式,字符串与 NULL 字符串的连接以及 UNIQUE 约束中对 NULL 的限制由其他标志处理。大多数 ORACLE 函数,如 TO_CHAR、TO_DATE、NVL 等已经内置。

目前,要使用简单的 ORACLE 类型,例如 NUMBER,您可以使用类型定义:

将类型编号创建为数字

设置标志时,下一个快照将允许 NUMBER(N) 和其他方面的 ORACLE 类型兼容性。

http://hsqldb.org/support/下载

[更新:] 10 月 4 日发布的快照将大多数 Oracle 特定类型转换为 ANSI SQL 类型。HSQLDB 2.0 也支持 ANSI SQL INTERVAL 类型和日期/时间戳算术,方式与 Oracle 相同。

于 2010-09-24T10:29:29.180 回答
2

你的单元测试是为了什么?如果他们测试 DDL 和存储过程的正常工作,那么您应该编写更接近 Oracle 的测试:要么没有 Java 代码,要么没有 Spring 和其他完全专注于 db 的漂亮 Web 界面。

如果您想测试在 Java 和 Spring 中实现的应用程序逻辑,那么您可以使用模拟对象/数据库连接来使您的测试独立于数据库。

如果您想测试整个工作(这违反了模块化开发和测试原则),那么您可以虚拟化您的数据库并在该实例上进行测试,而不会冒进行一些令人讨厌的不可逆修改的风险。

于 2010-09-24T07:12:07.620 回答
1

只要您的测试自行清理(因为您似乎已经知道如何设置),对真实数据库实例运行测试就没有错。事实上,这是我通常更喜欢的方法,因为您将测试尽可能接近生产的东西。

不兼容似乎很小,但不久之后真的会反咬一口。在一个好的情况下,你可能会逃脱一些讨厌的 sql 翻译/广泛的嘲弄。在糟糕的情况下,系统的某些部分将无法测试,我认为这对于关键业务系统来说是不可接受的风险。

于 2011-12-12T16:31:52.347 回答