12

我正在设置一个持续集成服务器 (Hudson) 来构建一个 Java 项目并运行相关的单元/集成测试。这些测试中的大多数都访问数据库,并且测试数据保存在 DbUnit XML 文件中。

我正在寻找一种自动保持测试数据库模式最新的方法。当前,特定发行版的 SQL 脚本存储在以发行版命名的目录中:

└───scripts
    ├───0.1.0
    ├───0.1.1
    ├───0.1.2
    ├───0.1.4

例如,版本 0.1.4 的 SQL 脚本是

scripts\0.1.4\script-0.1.4.sql

问题是这些脚本包含模式更改(例如 ALTER TABLE...)和静态表更改(例如向 USER_TYPE 表添加新角色)的混合。

在单元测试的情况下,我只想应用架构更改,因为如上所述,单元测试的所有数据都保存在 DbUnit XML 文件中。尽管我可以将这两种类型的数据库更改分离到不同的文件中,但架构更改和数据更改之间通常存在依赖关系,当发布应用于 QA、生产等时,需要以某种方式强制执行。

无论如何,这只是询问是否有人提出了一种强大的方法来自动保持他们的测试模式最新的一种非常冗长的方式?我知道Unitils对保持测试模式保持最新有一些支持,但我不确定它是否可以“忽略”SQL 增量脚本中的数据更新语句。

4

6 回答 6

4

之前的一张海报将 Liquibase 列为一个选项,但是他们没有提到 Liquibase 定义在特定上下文中运行的规则的能力(Liquibase中的上下文)。这允许您将架构更新不标记为任何特定上下文,并将单元测试的固定装置标记为test. 这样,只有在您运行单元测试时才会插入固定装置。

以下是包含架构和固定装置的 Liquibase 更改集示例:

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.9 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd">
  <changeSet author="avalade" id="1">
    <createTable tableName="users">
      <column autoIncrement="true" name="id" type="long">
        <constraints nullable="false" primaryKey="true" />
      </column>
      <column name="email" type="varchar(255)" />
    </createTable>
  </changeSet>
  <changeSet author="avalade" id="2" context="test">
    <insert tableName="user">
      <column name="id" value="1" />
      <column name="email" value="test@test.com" />
    </insert>
  </changeSet>
</databaseChangeLog>

然后,如果您使用 Spring 来管理您的 DAO,您可以将以下内容放入您正在部署的应用程序上下文文件中:

<bean id="liquibase" class="liquibase.spring.SpringLiquibase">
  <property name="dataSource" ref="dataSource" />
  <property name="changeLog" value="classpath:dbChangelog.xml" />
</bean>

对于您在单元测试中使用的应用程序上下文文件,请使用附加上下文属性配置 Liquibase:

<bean id="liquibase" class="liquibase.spring.SpringLiquibase">
  <property name="dataSource" ref="dataSource" />
  <property name="changeLog" value="classpath:dbChangelog.xml" />
  <property name="contexts" value="test" />
</bean>

这样,您可以将所有数据库定义放在一个地方,并且仅在运行测试代码时插入您的固定装置。

于 2009-06-11T22:12:45.890 回答
3

我们发现管理实时/测试数据库模式逐渐演变的最易于管理的方法是使用像Liquibase这样的模式迁移管理工具

这允许我们以一致的方式将最新的模式更改应用于我们选择、测试或其他方式的任何环境,然后允许我们针对最新模式运行我们希望的任何类型的自动化。

于 2009-01-20T15:03:25.597 回答
2

我目前使用类似的方法。我一直在研究数据库迁移工具,但没有找到解决您描述的问题的工具。

问题是,有时模式更改需要更改数据以允许创建新的约束等......在这种情况下,如果忽略数据更新语句,迁移将失败。

将删除数据库中所有数据的 sql 脚本添加到您的测试套件对您有用吗?

所以这个过程是:

  1. 运行数据库迁移。
  2. 运行脚本以删除数据库中的所有数据。
  3. 加载测试数据
  4. 运行测试
于 2009-01-20T16:26:09.207 回答
2

我在测试中做了什么:

  • 我在某处保留了数据库版本
  • 在第一个测试中,我拆除了整个数据库并从头开始构建它
  • 我在单独的测试中运行每个模式更新
  • 我将“更新数据库”模块作为单独的测试运行(不能做任何事情,因为所有更改都已应用)。或者,我再次拆除数据库并运行一次。
  • 我将测试数据加载到数据库中(如果它们修复数据错误,上面的一些测试会这样做)。

现在,测试数据库已准备好进行“真实”(应用程序)测试。在每个应用程序测试之后,我回滚当前事务,以便测试数据库在设置后永远不会更改。

为了使测试更快,我通常有三个测试套件:一个包含数据库设置,一个仅包含应用程序测试,另一个包含其他两个套件。这使我可以快速重置测试数据库并从应用程序套件运行单个测试。

于 2009-01-20T15:00:12.827 回答
1

我使用migrateDB来管理这个问题。

该工具基于这样一种概念,即您可以(通过 SQL)在数据库上执行“测试”以查看是否应用了给定的数据库更改,以及在测试“失败”时执行的相关操作集。例如,您可能需要查询元表模式以查看表或列是否存在,如果不存在,则创建它。或者,您可能想查看表中是否存在某一行,如果不存在,则插入它。它带有一些预先配置的常见测试和操作,并且很容易添加您自己的(仅使用 XML 配置 - 不需要新代码来执行此操作。)

作为一个小奖励,这些测试和操作中的每一个都是为 SQL 的每个“方言”配置的(例如,您可以有一个“oracle”方言和一个“mySQL”方言。)这意味着一旦你定义了查询对于每种方言的给定测试和操作,测试或操作的每个新实例都不需要新的 SQL,并且可以针对多个目标数据库执行。

然后,您只需维护一个列出测试和相应操作的小型 XML 文件,并在每次构建后针对您的数据库运行该工具。

它对我们来说效果很好。

于 2009-01-20T15:33:00.827 回答
0

这是我们所做的:

$ find src/sql/ | grep -v /.svn
src/sql/
src/sql/0000-system.sql
src/sql/0000-system.sql.dev.log
src/sql/0000-system.sql.prod.log
src/sql/0000-system.sql.test.log
src/sql/0001-usgn.sql
src/sql/0001-usgn.sql.dev.log
src/sql/0001-usgn.sql.prod.log
src/sql/0001-usgn.sql.test.log
src/sql/0002-usgn.sql
src/sql/0002-usgn.sql.dev.log
src/sql/0002-usgn.sql.prod.log
src/sql/0002-usgn.sql.test.log
src/sql/0003-usgn.sql
src/sql/0003-usgn.sql.dev.log
src/sql/0003-usgn.sql.prod.log
src/sql/0003-usgn.sql.test.log
src/sql/0004-system.sql
src/sql/0004-system.sql.dev.log
src/sql/0005-usgn.sql
src/sql/purge.sql

我们有scriptseq###-databaseusercredential.sql

现在我们的测试,总是允许数据库中数据的未知起始状态。如果您不能这样做,那么我建议您使用 SEQ-CRED-TYPE.sql,其中类型为 dml / ddl 并过滤掉 dml 脚本。

于 2009-04-26T16:52:19.457 回答