<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    MicroFish

    Open & Open hits
    隨筆 - 33, 文章 - 2, 評論 - 4, 引用 - 0
    數據加載中……

    (轉)用DbUnit進行SqlMap單元測試- -

    http://starrynight.blogdriver.com/starrynight/621943.html
    DbUnit簡介

    為依賴于其他外部系統(如數據庫或其他接口)的代碼編寫單元測試是一件很困難的工作。在這種情況下,有效的單元必須隔離測試對象和外部依賴,以便管理測試對象的狀態和行為。

    使用mock object對象,是隔離外部依賴的一個有效方法。如果我們的測試對象是依賴于DAO的代碼,mock object技術很方便。但如果測試對象變成了DAO本身,又如何進行單元測試呢?

    開源的DbUnit項目,為以上的問題提供了一個相當優雅的解決方案。使用DbUnit,開發人員可以控制測試數據庫的狀態。進行一個DAO單元測試之前,DbUnit為數據庫準備好初始化數據;而在測試結束時,DbUnit會把數據庫狀態恢復到測試前的狀態。

    下面的例子使用DbUnit為iBATIS SqlMap的DAO編寫單元測試。

    準備測試數據
    首先,要為單元測試準備數據。使用DbUnit,我們可以用XML文件來準備測試數據集。下面的XML文件稱為目標數據庫的Seed File,代表目標數據庫的表名和數據,它為測試準備了兩個Employee的數據。employee對應數據庫的表名,employee_uid、start_date、first_name和last_name都是表employee的列名。

    <?xml version="1.0" encoding="GB2312"?>
    <dataset>
    ??? <employee employee_uid="0001"
    ??? ??? start_date="2001-01-01"
    ??? ??? first_name="liutao"
    ??? ??? last_name="liutao" />
    ???
    ??? <employee employee_uid="0002"
    ??? ??? start_date="2001-04-01"
    ??? ??? first_name="wangchuang"
    ??? ??? last_name="wangchuang" />
    </dataset>

    缺省情況下,DbUnit在單元測試開始之前刪除Seed File中所有表的數據,然后導入Seed File的測試數據。在Seed File中不存在的表,DbUnit則不處理。
    Seed File可以手工編寫,也可以用程序導出現有的數據庫數據并生成。

    SqlMap代碼
    我們要測試的SqlMap映射文件如下所示:
    <select id="queryEmployeeById" parameterClass="java.lang.String"
    ??? resultClass="domain.Employee">
    ??? select employee_uid as userId,
    ??? ??? start_date as startDate,
    ??? ??? first_name as firstName,
    ??? ??? last_name as lastName
    ??? from EMPLOYEE where employee_uid=#value#
    </select>
    <delete id="removeEmployeeById" parameterClass="java.lang.String">
    ??? delete from EMPLOYEE where employee_uid=#value#
    </delete>
    <update id="updateEmpoyee" parameterClass="domain.Employee">
    ??? update EMPLOYEE
    ??? set start_date=#startDate#,
    ??? first_name=#firstName#,
    ??? last_name=#lastName#
    ??? where employee_uid=#userId#
    </update>
    <insert id="insertEmployee" parameterClass="domain.Employee">
    ??? insert into employee (employee_uid,
    ??? ??? start_date, first_name, last_name)
    ??? ??? values (#userId#, #startDate#, #firstName#, #lastName#)
    </insert>

    編寫DbUnit TestCase
    為了方便測試,首先為SqlMap的單元測試編寫一個抽象的測試基類,代碼如下。

    public abstract class BaseSqlMapTest extends DatabaseTestCase {
    ??? protected static SqlMapClient sqlMap;

    ??? protected IDatabaseConnection getConnection() throws Exception {
    ??? ??? return new DatabaseConnection(getJdbcConnection());
    ??? }
    ??? protected void setUp() throws Exception {
    ??? ??? super.setUp();
    ??? ??? init();
    ??? }
    ??? protected void tearDown() throws Exception {
    ??? ??? super.tearDown();
    ??? ??? getConnection().close();
    ??? ??? if (sqlMap != null) {
    ??? ??? ??? DataSource ds = sqlMap.getDataSource();
    ??? ??? ??? Connection conn = ds.getConnection();
    ??? ??? ??? conn.close();
    ??? ??? }
    ??? }
    ??? protected void init() throws Exception {
    ??? ??? initSqlMap("sqlmap/SqlMapConfig.xml", null);
    ??? }
    ??? protected SqlMapClient getSqlMapClient() {
    ??? ??? return sqlMap;
    ??? }
    ??? protected void initSqlMap(String configFile, Properties props)
    ??? ??? ??? throws Exception {
    ??? ??? Reader reader = Resources.getResourceAsReader(configFile);
    ??? ??? sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader, props);
    ??? ??? reader.close();
    ??? }
    ??? protected void initScript(String script) throws Exception {
    ??? ??? DataSource ds = sqlMap.getDataSource();
    ??? ??? Connection conn = ds.getConnection();
    ??? ???
    ??? ??? Reader reader = Resources.getResourceAsReader(script);
    ??? ??? ScriptRunner runner = new ScriptRunner();
    ??? ??? runner.setStopOnError(false);
    ??? ??? runner.setLogWriter(null);
    ??? ??? runner.setErrorLogWriter(null);

    ??? ??? runner.runScript(conn, reader);
    ??? ??? conn.commit();
    ??? ??? conn.close();
    ??? ??? reader.close();
    ??? }
    ??? private Connection getJdbcConnection() throws Exception {
    ??? ??? Properties props = new Properties();
    ??? ??? props.load(Resources.getResourceAsStream("sqlmap/SqlMapConfig.properties"));
    ??? ??? Class driver = Class.forName(props.getProperty("driver"));
    ??? ??? Connection conn = DriverManager.getConnection(props.getProperty("url"),
    ??? ??? ??? ??? props.getProperty("username"), props.getProperty("password"));
    ??? ??? return conn;
    ??? }
    }

    然后為每個SqlMap映射文件編寫一個測試用例,extends上面的抽象類。如編寫Employ.xml的測試用例如下,它覆蓋了DbUnit的DatabaseTestCase類的getDataSet方法。

    public class EmployeeDaoTest extends BaseSqlMapTest {
    ???
    ??? protected IDataSet getDataSet() throws Exception {
    ??? ??? Reader reader = Resources.getResourceAsReader("config/employee_seed.xml");
    ??? ??? return new FlatXmlDataSet(reader);
    ??? }
    ??? public void testQueryEmpoyeeById() throws Exception {
    ??? ??? String id = "0001";
    ??? ??? Employee emp = (Employee)sqlMap.queryForObject("queryEmployeeById", id);
    ??? ??? assertNotNull(emp);
    ??? ??? assertEquals("0001", emp.getUserId());
    ??? ??? assertEquals("liutao", emp.getFirstName());
    ??? }
    ??? public void testRemoveEmployeeById() throws Exception {
    ??? ??? String id = "0001";
    ??? ??? int num = sqlMap.delete("removeEmployeeById", id);
    ??? ??? assertEquals(1, num);
    ??? ???
    ??? ??? // 注意這里, 確認刪除不能使用SqlMap的查詢, 很奇怪!
    ??? ??? ITable table = getConnection().createQueryTable("removed",
    ??? ??? ??? ??? "select * from employee where employee_uid='0001'");
    ??? ??? assertEquals(0, table.getRowCount());
    ??? }
    ??? public void testUpdateEmployee() throws Exception {
    ??? ??? String id = "0002";
    ??? ??? Employee emp = (Employee)sqlMap.queryForObject("queryEmployeeById", id);
    ??? ??? emp.setLastName("wch");
    ??? ??? sqlMap.update("updateEmpoyee", emp);
    ??? ???
    ??? ??? Employee emp1 = (Employee)sqlMap.queryForObject("queryEmployeeById", id);
    ??? ??? assertEquals("wch", emp1.getLastName());
    ??? }
    ??? public void testInsertEmployee() throws Exception {
    ??? ??? Employee emp = new Employee();
    ??? ??? emp.setUserId("0005");
    ??? ??? emp.setStartDate("2003-09-09");
    ??? ??? emp.setFirstName("macy");
    ??? ??? emp.setLastName("macy");
    ??? ??? sqlMap.insert("insertEmployee", emp);
    ??? ???
    ??? ??? Employee emp1 = (Employee)sqlMap.queryForObject("queryEmployeeById", "0005");
    ??? ??? assertEquals(emp.getFirstName(), emp1.getFirstName());
    ??? ??? assertEquals(emp.getStartDate(), emp1.getStartDate());
    ??? }
    }

    以上例子中的綠色代碼部分使用ITable接口來查詢已刪除的數據。因為使用SqlMapClient.queryForObject方法查詢,已刪除的數據還存在,真奇怪(有時間再研究)。

    DbUnit的斷言
    我們可以使用DbUnit的Assertion類的方法來比較數據是否相同。

    public class Assertion {
    ??? public static void assertEquals(ITable expected, ITable actual)
    ??? public static void assertEquals(IDataSet expected, IDataSet actual)
    }

    DatabaseTestCase的getSetUpOperation和getTearDownOperation方法
    缺省情況下,DbUnit執行每個測試前,都會執行CLEAN_INSERT操作,刪除Seed File中所有表的數據,并插入文件的測試數據。你可以通過覆蓋getSetUpOperation和getTearDownOperation方法改變setUp和tearDown的行為。

    protected DatabaseOperation getSetUpOperation() throws Exception {
    ??? return DatabaseOperation.REFRESH;
    }
    protected DatabaseOperation getTearDownOperation() throws Exception {
    ???
    return DatabaseOperation.NONE;
    }

    REFRESH操作執行測試前并不執行CLEAN操作,只是導入文件中的數據,如果目標數據庫數據已存在,DbUnit使用文件的數據來更新數據庫。

    使用Ant
    上面的方法通過extends DbUnit的DatabaseTestCase來控制數據庫的狀態。而
    使用DbUnit的Ant Task,完全可以通過Ant腳本的方式來實現。

    <taskdef name="dbunit" classname="org.dbunit.ant.DbUnitTask"/>
    <!-- 執行set up 操作 -->
    <dbunit driver="org.hsqldb.jdbcDriver"
    ??????? url="jdbc:hsqldb:hsql://localhost/xdb"
    ??????? userid="sa" password="">
    ??? <operation type="INSERT" src="employee_seed.xml"/>
    </dbunit>
    <!-- run all tests in the source tree -->
    <junit printsummary="yes" haltonfailure="yes">
    ? <formatter type="xml"/>
    ? <batchtest fork="yes" todir="${reports.tests}">
    ??? <fileset dir="${src.tests}">
    ????? <include name="**/*Test*.java"/>
    ??? </fileset>
    ? </batchtest>
    </junit>
    <!-- 執行tear down 操作 -->
    <dbunit driver="org.hsqldb.jdbcDriver"
    ??????? url="jdbc:hsqldb:hsql://localhost/xdb"
    ??????? userid="sa" password="">
    ??? <operation type="DELETE" src="employee_seed.xml"/>
    </dbunit>

    以上的Ant腳本把junit task放在DbUnit的Task中間,可以達到控制數據庫狀態的目標。

    由此可知,DbUnit可以靈活控制目標數據庫的測試狀態,從而使編寫SqlMap單元測試變得更加輕松。

    本文抄襲了資源列表的“Effective Unit Test with DbUnit”,但重新編寫了代碼示例。

    網上資源

    1、DbUnit Framework

    2、Effective Unit Testing with DbUnit

    3、Control your test-environement with DbUnit and Anthill

    posted on 2007-03-26 17:16 劉璐 閱讀(740) 評論(0)  編輯  收藏 所屬分類: other

    主站蜘蛛池模板: 亚洲AV无码一区二三区| 亚洲精品国产av成拍色拍| 麻豆安全免费网址入口| 成人爽A毛片免费看| 亚洲中文久久精品无码1| 69av免费观看| 亚洲精品在线播放视频| 在线日本高清免费不卡| 真正全免费视频a毛片| 麻豆国产精品入口免费观看| 亚洲中文字幕一二三四区| 无码一区二区三区免费视频 | 亚洲人成色77777在线观看大| 亚洲s码欧洲m码吹潮| 国产大片免费观看中文字幕| 中文亚洲成a人片在线观看| 一道本不卡免费视频| 亚洲一级特黄大片在线观看 | 无码av免费一区二区三区| 久久久久久久综合日本亚洲| 免费看一区二区三区四区| 亚洲视频.com| 欧美日韩国产免费一区二区三区| 亚洲国产成人久久精品软件| 亚洲国产成人久久精品99| 国产在线观a免费观看| 亚洲高清资源在线观看| 成人无遮挡毛片免费看| 伊人久久综在合线亚洲2019| 狼人大香伊蕉国产WWW亚洲| 亚洲国产精品综合久久网络| 久久精品一区二区免费看| 亚洲精品在线不卡| 国产精品无码一二区免费| 成人免费夜片在线观看| 亚洲国产精品不卡在线电影| 午夜视频在线在免费| 久久九九久精品国产免费直播| 77777_亚洲午夜久久多人| 国产精品免费视频网站| 久久久久国色av免费看|