<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 劉璐 閱讀(733) 評論(0)  編輯  收藏 所屬分類: other

    主站蜘蛛池模板: 免费观看毛片视频| 亚洲伊人久久精品影院| 亚洲av中文无码乱人伦在线观看| 内射无码专区久久亚洲| 一级毛片aaaaaa免费看| 亚洲精华液一二三产区| 久久久久久a亚洲欧洲aⅴ| 无码av免费毛片一区二区| 色多多A级毛片免费看| 亚洲精品欧洲精品| 亚洲国产成人精品91久久久| 久久A级毛片免费观看| 男男gay做爽爽的视频免费| 亚洲国产一区二区三区青草影视| 午夜视频免费成人| 久久国产精品免费专区| 羞羞网站在线免费观看| 亚洲成人网在线播放| 亚洲五月综合缴情在线观看| 德国女人一级毛片免费| 十八禁无码免费网站| 男女啪啪免费体验区| 亚洲宅男精品一区在线观看| 国产∨亚洲V天堂无码久久久| 免费看美女让人桶尿口| 亚洲一区二区三区免费视频| 美女巨胸喷奶水视频www免费| 亚洲欧美乱色情图片| 亚洲欧洲精品一区二区三区| 国产成人综合亚洲AV第一页| 破了亲妺妺的处免费视频国产 | 豆国产96在线|亚洲| 久久精品a亚洲国产v高清不卡| 亚洲精品久久久www| 日韩免费三级电影| 国产情侣激情在线视频免费看| 国产va在线观看免费| 国产免费内射又粗又爽密桃视频 | 久久性生大片免费观看性| 另类小说亚洲色图| 春暖花开亚洲性无区一区二区|