Java 持续集成:使测试数据库模式保持最新
我正在设置一个持续集成服务器(Hudson)来构建一个Java项目并运行相关的单元/集成测试。大多数测试访问数据库,测试数据保存在dbunitxml文件中 我正在寻找一种方法来自动使测试数据库模式保持最新。当前,特定版本的SQL脚本存储在以发布版本命名的目录中:Java 持续集成:使测试数据库模式保持最新,java,unit-testing,continuous-integration,hudson,Java,Unit Testing,Continuous Integration,Hudson,我正在设置一个持续集成服务器(Hudson)来构建一个Java项目并运行相关的单元/集成测试。大多数测试访问数据库,测试数据保存在dbunitxml文件中 我正在寻找一种方法来自动使测试数据库模式保持最新。当前,特定版本的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
└───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表添加新角色)
对于单元测试,我只想应用模式更改,因为如上所述,单元测试的所有数据都保存在dbunitxml文件中。虽然我可以将这两种类型的数据库更改分离到不同的文件中,但模式更改和数据更改之间通常存在依赖关系,当版本应用于QA、生产等时,这些更改需要以某种方式强制执行
无论如何,这只是一种冗长的方式,询问是否有人提出了一种健壮的方法来自动保持他们的测试模式最新?我知道有一些支持使测试模式保持最新,但我不确定它是否可以“忽略”SQL增量脚本中的数据更新语句。我在测试中的操作:
- 我在某处保存了一个DB版本
- 在第一次测试中,我拆掉了整个数据库,从头开始构建它
- 我在一个单独的测试中运行每个模式更新
- 我将“updatedb”模块作为一个单独的测试运行(不得执行任何操作,因为所有更改都已应用)。或者,我再次拆掉数据库并运行一次
- 我将测试数据加载到数据库中(如果上面的一些测试修复了数据错误,它们将执行此操作)
为了加快测试速度,我通常有三个测试套件:一个包含DB设置,一个只包含应用程序测试,另一个包含其他两个套件。这使我能够快速重置测试数据库,并从应用程序套件中运行单个测试。我们发现,管理live/test DB模式渐进演变的最易管理的方法是使用模式迁移管理工具,如 这使我们能够以一致的方式将最新的模式更改应用到我们选择、测试或其他的任何环境中,从而允许我们根据最新的模式运行我们希望的任何类型的自动化。我用来管理此问题 该工具基于这样的概念,即您可以(通过SQL)对数据库执行“测试”,以查看是否已应用给定的数据库更改,以及在测试“失败”时要执行的相关操作集。例如,您可能需要查询元表架构,以查看是否存在表或列,如果不存在,则创建它。或者,您可能希望查看表中是否存在某一行,如果不存在,请插入该行。它附带了一些预配置的常见测试和操作,并且很容易添加自己的测试和操作(只需XML配置,无需新代码即可完成此操作) 另外,这些测试和操作中的每一个都是为SQL的每一种“方言”配置的(例如,您可以使用“oracle”方言和“mySQL”方言)。这意味着,一旦您为每个方言的给定测试和操作定义了查询,测试或操作的每个新实例就不需要新的SQL,并且可以针对多个目标数据库执行 然后,您只需维护一个小XML文件,其中列出了测试和相应的操作,并在每次构建之后针对您的数据库运行该工具
它对我们来说非常有效。我目前使用类似的方法。我一直在研究数据库迁移工具,但没有找到一个能够解决您描述的问题的工具 问题是,有时模式更改需要更改数据以允许创建新的约束,等等。。。在这种情况下,如果忽略数据更新语句,迁移将失败 向测试套件中添加删除数据库中所有数据的sql脚本对您有用吗 因此,这一过程将是:
$ 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,其中TYPE为dml/ddl,并过滤掉dml脚本。之前的海报将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>
这样,您可以将所有数据库定义放在一个地方,并且在运行测试代码时只插入fixture