JUnit + DbUnit:在开发和测试环境之间切换数据库连接

Posted

技术标签:

【中文标题】JUnit + DbUnit:在开发和测试环境之间切换数据库连接【英文标题】:JUnit + DbUnit: Switch database connection between development and testing environments 【发布时间】:2012-05-29 04:21:59 【问题描述】:

我正在围绕现有项目设置一些测试脚手架。这包括一些使用 JUnit 和 DbUnit 的集成测试。我还为持续集成设置了 Jenkins 安装。

我的问题涉及更改开发和测试环境之间的数据库连接。我在本地安装了自己的产品堆栈,以进行快速的临时测试和调查。在开发过程中,我会针对我的私有数据库运行测试,因为它速度更快,而且我不会用有缺陷的正在进行的代码破坏任何人的一天。

签入代码后,Jenkins 将运行我的测试。现在它仍然指向我的本地数据库。我宁愿让 Jenkins 针对不同的数据库运行测试,该数据库位于测试环境中。

是否有最佳实践/策略/技术/等来更改数据库连接以进行测试而无需更改代码?如果该解决方案允许 Jenkins 对多个 DB 运行相同的测试(应该是可能的,因为 DbUnit 是不可知的),则可以加分。


编辑以获取更多信息:

产品很大,有几十个不同的交互组件(通常在单独的虚拟机/进程中)。在实时系统中,不同的进程通常通过数据库进行通信。 IE,UI 进程将更改写入表,后端进程轮询该表以进行更改。是的,这很糟糕。对于集成测试,我使用 UI 配置系统并使用 DbUnit 捕获该状态。然后我可以针对该“输入”运行测试。

我的组件和所有新组件都由 maven 管理。数据库连接当前在测试设置中是硬编码的。 DbUnit 系统有效;我希望能够根据测试是由我在我的开发环境中运行,还是由 Jenkins 在测试环境中运行来切换我的测试引用的数据库。

【问题讨论】:

【参考方案1】:

假设您可以将测试的数据库连接参数外部化到 .properties.xml 文件中,并且您正在使用 Maven,那么一种方法是使用 Maven 属性(以及可选的配置文件)来定义每个环境,并使用资源过滤将这些属性配置到您的配置文件中。

例如,假设在测试期间,您设法将数据库连接参数外部化到一个名为 datasource.properties 的文件中,该文件位于 src/test/resources 中,如下所示:

datasource.driverClassName = $test.datasource.driverClassName
datasource.url = $test.datasource.url
datasource.username = $test.datasource.username
datasource.password = $test.datasource.password

你的 POM 中有这个:

<build>
  <testResources>
    <testResource>
      <directory>src/test/resources</directory>
      <filtering>true</filtering>
    </testResource>
  </testResources>
</build>

然后你可以通过各种方式定义test.datasource.driverClassName等属性来告诉Maven使用不同的数据库:

您可以在 POM 的 &lt;properties&gt; 部分定义默认值; 您可以在每个开发人员(和 Jenkins')settings.xml&lt;properties&gt; 部分中定义用户特定的数据库; 您可以在 POM 中为不同的环境定义一些配置文件(例如developmentjenkinsanotherDB)并使用不同的配置文件运行您的构建。

如果您选择最后一个选项,那么您可以通过从一个 Jenkins 项目执行多个 Maven 构建来让 Jenkins 针对多个数据库运行,仅在配置文件上有所不同。也就是说,最好为每个环境使用不同的 Jenkins 项目。

【讨论】:

【参考方案2】:

需要了解有关您的构建工具的更多信息。你在使用 Maven 吗?您的数据库连接信息存储在哪里?你用的是弹簧吗?

我目前这样做,我将 Maven 与我的主数据库连接的属性和一组单独的属性用于我的测试数据库连接。

由于我使用 Spring,在 maven 测试资源中,我有一个 applicationContext 文件,其中包含我的数据源 bean 并引用测试属性。

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-    method="close">
    <property name="driverClassName" value="$test.jdbc.driverClassName"/>
    <property name="url" value="$test.jdbc.url"/>
    <property name="username" value="$test.jdbc.username"/>
    <property name="password" value="$test.jdbc.password"/>
    <property name="maxActive" value="100"/>
    <property name="maxWait" value="1000"/>
    <property name="poolPreparedStatements" value="true"/>
    <property name="defaultAutoCommit" value="true"/>
</bean>

【讨论】:

谈到 Spring 时,我感到非常尴尬,但我所知道的一点点让我相信它可能是一个有用的解决方案。我的印象是您在 xml 中配置了数据源,并注释了您的类以进行运行时依赖注入。 Spring 是否能够根据环境(开发与测试)更改注入的数据库? 您在 XML 中配置数据库连接是正确的。但是对于您要完成的工作,我认为您确实应该关注 Maven 将为您做什么,以及如何利用构建的 Maven 属性和配置文件来自定义构建和运行测试。 Maven 可以运行您的单元测试,并且它具有仅在测试阶段使用的资源,然后它可以将另一组资源用于您的主要构建,即进入任何环境。 Jenkins 运行 maven 构建,因此您可以在您的机器上模拟 Jenkins 将要做的完全相同的事情。【参考方案3】:

很大程度上取决于您的部署环境。如果您要部署到容器(tomcat、jboss 等),那么使用 JNDI 连接会将您与 DB 环境隔离开来。如果您正在构建一个独立的 java 程序,那么您必须自己确定环境,并选择要使用的数据库连接配置文件。

一种方法是为每个环境单独配置数据库,并将其包含在您的部署中。这样您就不必担心您所处的环境而使您的代码复杂化。

另一种方法是将环境传递给您的程序,让您的代码确定要使用的配置。

【讨论】:

我已经编辑了我的帖子以包含更多信息。我很好奇你提到的“单独的数据库配置”的格式。那是一个 .properties 文件(使用 ResourceBundle),还是一个 XML(使用其他工具),或者完全是其他东西?我可以将 jdbc 连接字符串放在一个文件中并读取该文件,但这感觉很hackish。我的假设是存在一种工具/实践/格式可以以更标准的方式做到这一点。我只是不知道标准是什么。 .propreties 文件或 XML。我自己会使用 .properties 文件,我非常鄙视 XML。

以上是关于JUnit + DbUnit:在开发和测试环境之间切换数据库连接的主要内容,如果未能解决你的问题,请参考以下文章

转:使用DBUnit测试时违反外键约束的解决办法

Spring Test Dbunit,H2数据库

DBUnit使用案例

DBUnit数据库测试

DBUnit数据库测试

DBUnit数据库测试