环境背景:
我作为项目经理和技术架构管理人员负责公司一条生产线。讨论之后,首席架构师希望我们能够实施TDD。在实施TDD的过程中,设计实施过程的整体思路就是:单元测试用例文档 - 实施单元测试 - 实施业务代码 – 修改业务代码逻辑。实施人员需要参与每个环节,按照规范编写单元测试用例文档。单元测试我们按照模块(模块与人员基本没有重合)划分包(suite),保证实施起来不会产生干扰。。技术架构决定采用:maven,junit,svn。
技术背景:
技术架构设计上,我们封装了dao层的实现,所以实施人员基本无需涉及dao层的开发。服务层我们采用了JAX-RS的服务规范,对外开发服务接口。
在测试覆盖率方面,我们基本不要求对dao层的单元测试,但要求在服务层的单元测试达到100%。由于服务层是Restful WS的模式,所以我们采用了模拟HTTP请求的方式在测试服务层。
由于需要模拟HTTP的请求,所以我们在单元测试中采用了jetty作为内嵌服务器,单元测试开始时同一启动,完成后关闭。
实施过程:
开发过程中,实际实施的时候发现一个问题,对于测试数据的管理问题。即测试当中需要一定的数据环境来验证业务逻辑。这个数据环境如何建立?
方案一,使用dbunit和hsqldb。在测试启动时重建数据环境。
否决,原因:
1.与实际运行环境差异较大。
2.反复重建数据环境,效率上有缺失。
3.技术架构增加,学习和维护曲线较大。
讨论后决定使用
方案二,独立出一套测试数据库,完整数据环境。考虑到增删改与查询的冲突,制定默认规则,如id在20之内的不允许进行任何改动。以尽量隔离增删改的影响。
针对方案二,有一个较大的问题,如何在开发过程中自由的切换数据库配置呢?由于我们还是用了Hudson作为CI服务器,还要考虑到打包的过程。整体考虑之后,有两个步骤需要注意:
一、开发过程。开发过程中,我们将配置直接指向测试数据库。
二、打包过程。使用了maven,存在单元测试配置与最终产品配置的冲突。
所以最终问题的焦点集中在打包过程的maven配置方案。
搜索之后比较好的资料有
MAVEN:如何为开发和生产环境建立不同的配置文件 --我的简洁方案
(http://www.blogjava.net/scud/archive/2010/10/27/336326.html)
这篇博客是介绍在maven 中使用mvn package -P test 这样的自定义profile来实现的。这样是可行的,但是在Hudson中无法实现一条命令切换两套配置。
于是继续寻找,最终在maven的官方网站找到《Building For Different Environments with Maven 2》(http://maven.apache.org/guides/mini/guide-building-for-different-environments.html)看完文章之后发现,实际maven提供了一个非常好的插件maven-antrun-plugin,以实现某些ant的功能。此处还需要了解的知识就是maven的构建生命周期标准(http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)。基于上述两个知识点,我们制定出如下方案,在项目中建立测试配置目录及产品配置目录,在maven的package阶段开始前,都使用测试配置,运行集成测试,完成在package阶段前将产品配置覆盖至打包文件夹内,然后进行打包。思路就是这样,下面贴出pom文件的关键部分。
POM.xml
<!—profile 节点定义覆盖文件的方式内容 -->
<profiles>
<profile>
<id>product</id>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>pre_product</id>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<!—此处与ant的任务相似 -->
<tasks>
<delete file="${project.build.outputDirectory}/spring/dataSourceContext.xml" />
<delete file="${project.build.outputDirectory}/log4j.properties" />
<copy file="src/product/assembly/log4j.properties" tofile="${project.build.outputDirectory}/log4j.properties" />
<copy file="src/product/assembly/spring/dataSourceContext.xml" tofile="${project.build.outputDirectory}/spring/dataSourceContext.xml" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<!—构建过程 -->
<build>
<!—指定资源目录 -->
<resources>
<resource>
<directory>src/test/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
<resource>
<directory>src/test/assembly</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
<finalName>po</finalName>
<!—指定集成测试配置 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.3</version>
<configuration>
<junitArtifactName>junit:junit</junitArtifactName>
<forkMode>once</forkMode>
</configuration>
<executions>
<execution>
<id>default-test</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>false</skip>
<includes>
<include>**/*TestSuitex.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>