2009-01-20 86 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> 

這樣,您可以將所有數據庫定義保存在一個地方,並且只在您運行測試代碼時插入夾具。