<ruby id="rxdll"></ruby><strike id="rxdll"></strike>

    <rp id="rxdll"></rp>
      <del id="rxdll"><meter id="rxdll"></meter></del>
      <pre id="rxdll"><font id="rxdll"></font></pre>
        <pre id="rxdll"></pre>
      <p id="rxdll"><thead id="rxdll"></thead></p><dl id="rxdll"><progress id="rxdll"><form id="rxdll"></form></progress></dl>

      <ol id="rxdll"><thead id="rxdll"><track id="rxdll"></track></thead></ol>
      <i id="rxdll"><dfn id="rxdll"></dfn></i>
      <font id="rxdll"><meter id="rxdll"></meter></font>

        <mark id="rxdll"><dfn id="rxdll"></dfn></mark>
        • 軟件測試技術
        • 軟件測試博客
        • 軟件測試視頻
        • 開源軟件測試技術
        • 軟件測試論壇
        • 軟件測試沙龍
        • 軟件測試資料下載
        • 軟件測試雜志
        • 軟件測試人才招聘
          暫時沒有公告

        字號: | 推薦給好友 上一篇 | 下一篇

        軟件單元測試的測試用例編寫方法

        發布: 2010-9-10 08:28 | 作者: 網絡轉載 | 來源: 領測軟件測試網采編 | 查看: 298次 | 進入軟件測試論壇討論

        領測軟件測試網

        數據庫表有了,我們接下來編寫DAO及其實現類:
        MILY: 宋體; mso-ascii-font-family: " Times Roman?; mso-hansi-font-family: ?Times New mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: mso-fareast-language: ZH-CN; mso-ansi-language: EN-US; mso-bidi-language: AR-SA?>DAO接口:
        /**
        * @author tao.youzt
        */
        public interface BizUrlDAO {
        public Object insert(BizUrlDO bizUrlDO);
        public int delete(String url);
        public BizUrlDO getByUrl(String url);
        }
        DAO實現類,該類繼承一個支持類,封裝了對數據庫的操作。

        /**
        * @author tao.youzt
        */
        public class BizUrlIbatisImpl extends GodzillaDaoSupport implements BizUrlDAO {
        private static final String GET_BY_URL = "SELECT-BIZ-URL";
        private static final String DELETE = "DELETE-BIZ-URL";
        private static final String INSERT = "INSERT-BIZ-URL";
        public int delete(String url) {
        return this.delete(DELETE, url);
        }
        public BizUrlDO getByUrl(String url) {
        return this.queryForObject(GET_BY_URL, url, BizUrlDO.class);
        }
        public Object insert(BizUrlDO bizUrlDO) {
        return this.insert(INSERT, bizUrlDO);
        }
        }
         
        DO領域對象
        /**
        * @author tao.youzt
        */
        public class BizUrlDO {
        private int id;
        private String url;
        private String email;
        private String name;
        // getter and setter
        }
        因為本文案例使用Spring作為底層框架,因此這里需要編寫Spring配置文件對DAO進行組裝。
        Godzilla-dao.xml
         
        Godzilla-db.xml
         
        DAO及其配置文件都已經準備完畢,我們接下來編寫測試用例。Spring為單元測試提供了很多有用的支持類,我們在這里使用的是:
         
        該類提供了POJO屬性自動注入的能力,只要為為你的屬性字段提供一個Set方法即可。下面我們來看完整的測試用例:
        /**
        * @author tao.youzt
        */
        public class TestBizUrlDAO extends AbstractDependencyInjectionSpringContextTests {
        private BizUrlDAO bizUrlDAO;
        @Override
        protected String[] getConfigLocations() {
        return new String[]{"godzilla-dao.xml","godzilla-db.xml"};
        }
        public void testInsert(){
        bizUrlDAO.insert(generateDO());
        assertNotNull(bizUrlDAO.getByUrl("www.easyjf.com"));
        }
        public void testDuplicateInsert(){
        bizUrlDAO.insert(generateDO());
        try{
        bizUrlDAO.insert(generateDO());
        assertFalse("Must throw an exception!",true);
        }catch(Exception e){
        assertTrue(true);
        }
        }
        public void testDelete(){
        bizUrlDAO.insert(generateDO());
        assertNotNull(bizUrlDAO.getByUrl("www.easyjf.com"));
        bizUrlDAO.delete("www.easyjf.com");
        assertNull(bizUrlDAO.getByUrl("www.easyjf.com"));
        }
        private BizUrlSynchronizeDO generateDO() {
        BizUrlDO bizUrlDO = new BizUrlDO();
        bizUrlDO.setUrl("www.easyjf.com");
        bizUrlDO.setName("EasyJWeb");
        bizUrlDO.setEmail("webmaster@easyjf.com");
        return bizUrlDO;
        }
        public void setBizUrlDAO(BizUrlSynchronzieDAO bizUrlDAO) {
        this.bizUrlDAO = bizUrlDAO;
        }
        }
         
        getConfigLocations()方法為AbstractDependencyInjectionSpringContextTests 提供配置,Spring會根據該配置文件自動注入bizUrlDAO屬性。testInsert()方法用于測試插入新數據,注意這里有個問題,如果數據庫中已經存在該URL的記錄,則應用會報錯,所以這里還要進行數據清除準備處理,我們稱之為“測試環境準備”,以后會用到該名詞;testDuplicateInsert()方法用于測試插入重復數據的情況,該方法同樣存在上面的問題;testDelete()方法用于測試刪除數據的情況,這里盡管準備了數據,但仍沒有考慮數據庫中已經有記錄的情況。
        綜上所述,盡管該測試類已經比較清晰,但仍然存在許多不足之處。我們將在后面的章節進行詳細分析,并給出解決方案。
        Callback Function & Template Method Pattern
        回調函數(Callback Function)和模板方法(Template Method)是軟件架構設計中最常用的兩種設計模式,這兩種設計模式在Spring框架中隨處可見。
        關于本節是否要詳細介紹回調函數(Callback Function)和模板方法(Template Method)模式的問題,筆者考慮了很長時間。因為網絡上對這兩種普遍使用的設計模式的定義層出不窮,各有各的道理,很難說誰是誰非。況且,針對不同的應用場景,這兩種模式也有許多變體,或者聯合使用。
        因此,筆者最終決定不在此處對這兩種模式做任何定義或引用,請讀者自行參閱相關文檔資料。
        回調函數和模板方法模式在單元測試中的應用
        上一節我們簡單的回顧了回調函數和模板方法模式,Spring框架中大量采用了這兩種設計模式,有興趣的讀者可以閱讀Spring框架代碼進一步鞏固對這兩種模式的理解和運用。本節將結合回調函數模式和模板方法模式對前面的測試用例進行重構,讀者可以在重構過程中逐步了解這兩種設計模式的運用。
        首先,讓我們簡單總結一下前面測試用例的問題:
        一、抽象層次太低,不夠通用?
        例如,對于getConfigLocations()方法,我們完全可以放到一個父類中實現,因為對于一個項目而言,其配置文件大多都是統一的,沒有必要在沒有測試類中都定義該方法。
        /**
        * DAL層測試支持類.
        *
        *
        * 除非特殊情況,所有DAO都要繼承此類.
        *
        * @author tao.youzt
        */
        public abstract class GodzillaDalTestSupport extends AbstractDependencyInjectionSpringContextTests {
        /*
        * @see org.springframework.test.AbstractDependencyInjectionSpringContextTests#getConfigLocations()
        */
        @Override
        protected final String[] getConfigLocations() {
        String[] configLocations = null;
        String[] customConfigLocations = getCustomConfigLocations();
        if (customConfigLocations != null && customConfigLocations.length > 0) {
        configLocations = new String[customConfigLocations.length + 2];
        configLocations[0] = "classpath:godzilla/dal/godzilla-db-test.xml";
        configLocations[1] = "classpath:godzilla/dal/godzilla-dao.xml";
        for (int i = 2; i < configLocations.length; i++) {
        configLocations[i] = customConfigLocations[i - 2];
        }
        return configLocations;
        } else {
        return new String[] { "classpath:godzilla/dal/godzilla-db-test.xml",
        "classpath:godzilla/dal/godzilla-dao.xml" };
        }
        }
        /**
        * 子類可以覆蓋該方法加載個性化配置.
        *
        * @return
        */
        protected String[] getCustomConfigLocations() {
        return null;
        }
        }
         
        如圖所示,我們提煉了一個抽象支持類,實現了getConfigLocations()方法,同時還提供了getCustomConfigLocations()方法供子類使用,子類可以通過重載該方法提供定制的配置。
        有了該支持類,具體測試類只需要繼承該類并編寫測試邏輯即可。
        二、缺少準備測試環境和清除測試數據的環節?
        對于大多數測試用例,可能都會涉及到初始化數據和清除測試數據的問題,最典型的就是數據庫操作,這也是本文采用數據庫操作作為案例的原因。那么如何實現呢?很顯然在每個測試方法中都編寫準備環境和清除測試數據的代碼是不合適的,因為大多數時候對于一個測試類而言,準備環境和清除數據的邏輯都是一樣的。聰明的你一定會想到定義兩個方法,一個初始化環境,一個清除測試數據。是的,就是這樣!
        /**
        * @author tao.youzt
        */
        public class TestBizUrlDAO extends AbstractDependencyInjectionSpringContextTests {
        private BizUrlDAO bizUrlDAO;
        @Override
        protected String[] getConfigLocations() {
        return new String[]{"godzilla-dao.xml","godzilla-db.xml"};
        }
        protected void setupEnv(){
        bizUrlDAO.delete("www.easyjf.com");
        }
        protected void cleanEnv(){
        bizUrlDAO.delete("www.easyjf.com");
        }
        public void testTemp(){
        setupEnv();
        bizUrlDAO.insert(generateDO());
        assertNotNull(bizUrlDAO.getByUrl("www.easyjf.com"));
        setupEnv();
        }
        }
        如你所見,我們在這里定義了setupEnv()和cleanEnv()兩個方法,分別用于初始化環境和清除測試數據,然后在測試方法開始和結束時分別調用這兩個方法。這的確達到了我們的目的,不用在每個測試方法中都編寫初始化和清除邏輯!但此時你一定發現在每個測試方法前后都調用setupEnv()和cleanEnv()也很不爽,那說明我們的抽象程度還不夠!那么該如何做的更好呢?
        這里該到模板方法(Template Method)模式發揮威力的時候了。我們將使用模板方法來繼續重構前面的案例。讓我們先來定義一個方法:
        /**
        * @author tao.youzt
        */
        public class TestBizUrlDAO extends AbstractDependencyInjectionSpringContextTests {
        private BizUrlDAO bizUrlDAO;
        @Override
        protected String[] getConfigLocations() {
        return new String[]{"godzilla-dao.xml","godzilla-db.xml"};
        }
        protected void setupEnv(){
        bizUrlDAO.delete("www.easyjf.com");
        }
        protected void cleanEnv(){
        bizUrlDAO.delete("www.easyjf.com");
        }
        public void testTemp(){
        //do test logic in this method
        execute();
        }
        protected void execute(){
        setupEnv();
        doTestLogic();
        setupEnv();
        }
        }
        相比之前的方法,我們這里已經有了一些進步,定義了一個execute方法,在該方法開始和結束分別執行初始化和清除邏輯,然后由doTestLogic()方法實現測試邏輯。實際測試方法中只要執行execute方法,并傳入測試邏輯就可以了。瞧,不經意間我們已經實現了模板方法模式——把通用的邏輯封轉起來,變化的部分由具體方法提供。怎么,不相信么?呵呵,設計模式其實并不復雜,就是前人解決通用問題的一些最佳實踐總結而已。
        此時你可能會說,TeseCase類已經提供了setUp()和tearDown()方法來做這件事情,我也想到了,哈哈!但這并不和本文產生沖突!
        問題似乎越來越清晰,但我們遭遇了一條無法跨越的鴻溝——如何才能把測試邏輯傳遞到execute方法中呢?單靠傳統的編程方法已經無法解決這個問題,因此我們必須尋找其他途徑。
        可能此時此刻你已經想到,本文另一個重要概念——回調方法模式還沒有用到,是不是該使用該模式了?沒錯,就是它了!我先把代碼給出,然后再詳細解釋。
        我們提供了一個抽象類TestExecutor,并定義一個抽象的execute方法,然后為測試類的execute方法傳入一個TestExecutor的實例,并調用該實例的execute方法。最后,我們的測試方法中只需要new一個TestExecutor,并在execute方法中實現測試邏輯,便可以按照預期的方式執行:準備測試環境-執行測試邏輯-清除測試數據。這便是一個典型的回調方法模式的應用!
        模板方法和回調函數模式說起來挺懸,其實也就這么簡單,明白了吧:)

        延伸閱讀

        文章來源于領測軟件測試網 http://www.k11sc111.com/

        32/3<123>

        關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
        版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
        北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
        技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

        軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

        国产女主播精品_国产片婬乱18一级毛片视频_国产午夜激无码av毛片不卡_国产精品欧美久久久天天影院
          <ruby id="rxdll"></ruby><strike id="rxdll"></strike>

          <rp id="rxdll"></rp>
            <del id="rxdll"><meter id="rxdll"></meter></del>
            <pre id="rxdll"><font id="rxdll"></font></pre>
              <pre id="rxdll"></pre>
            <p id="rxdll"><thead id="rxdll"></thead></p><dl id="rxdll"><progress id="rxdll"><form id="rxdll"></form></progress></dl>

            <ol id="rxdll"><thead id="rxdll"><track id="rxdll"></track></thead></ol>
            <i id="rxdll"><dfn id="rxdll"></dfn></i>
            <font id="rxdll"><meter id="rxdll"></meter></font>

              <mark id="rxdll"><dfn id="rxdll"></dfn></mark>