2009-01-20 56 views
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文件中。虽然我可以将这两种类型的数据库更改分为不同的文件,但是在将版本应用于质量检查,生产等时,模式更改和数据更改之间通常会存在依赖关系。

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

回答

2

我在我的测试中做什么:

  • 我保持一个DB版本某处
  • 在第一次测试,我推倒了整个数据库,并从头开始构建它
  • 我运行的每个架构更新在个别测试中
  • 我运行“更新数据库”模块作为单独的测试(由于所有更改已经应用,所以不得做任何事情)。或者,我再次拆下DB并运行一次。
  • 我将测试数据加载到数据库中(上面的一些测试会在修复数据错误时执行此操作)。

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

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

3

我们发现,以管理现场/测试数据库模式逐步演变的最可管理的方式是使用像Liquibase

模式迁移管理工具,这使我们能够应用最新的架构更改到任何环境中,我们所以选择,测试或其他方式,以一致的方式,然后允许我们运行任何类型的自动化,我们希望与最新的模式。

1

我用migrateDB来解决这个问题。

该工具基于以下概念:您可以在数据库上执行(通过SQL)以查看是否应用了给定数据库更改的“测试”,以及如果测试执行了相关的一组操作,失败“。例如,您可能需要查询元表模式以查看表或列是否存在,如果不存在,请创建它。或者,您可能想要查看表中是否存在某个行,如果没有,请插入它。它配备了一些预先配置好的常用测试和操作,并且添加自己的软件非常简单(仅使用XML配置 - 无需新代码即可完成此操作)。

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

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

它对我们来说效果很好。

2

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

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

会添加一个SQL脚本到您的测试套件,删除数据库中的所有数据为您工作吗?

所以这个过程将是:

  1. 运行数据库迁移。
  2. 运行脚本删除分贝中的所有数据。
  3. 负载测试数据
  4. 运行测试
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

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

4

之前的海报列出了Liquibase作为一个选项,但是他们没有提到Liquibase定义在特定情况下运行的规则的能力(Contexts in 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="[email protected]" /> 
    </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> 

这样,您可以将所有数据库定义保存在一个地方,并且只在您运行测试代码时插入夹具。