環境背景:
我作為項目經理和技術架構管理人員負責公司一條生產線。討論之后,首席架構師希望我們能夠實施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.tkk7.com/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>