測試驅動開發(fā)(TDD)

測試驅動開發(fā)(Test-driven development)在維基百科上的定義是一種軟件開發(fā)過程中的應用方法,由極限編程中倡導,以其倡導先寫測試程序,然后編碼實現(xiàn)其功能得名。測試驅動開發(fā)始于20世紀90年代。測試驅動開發(fā)的目的是取得快速反饋并使用“illustrate the main line”方法來構建程序。簡單來說,就是從用戶的角度先編寫測試用例,再實現(xiàn)功能代碼,再進行重構和代碼測試。

現(xiàn)在就以liteStruts為例,簡要說明TDD開發(fā)的過程。liteStruts所要實現(xiàn)的功能是讀取struts.xml,執(zhí)行Action,例如用戶需要登錄(login),發(fā)出請求后,web應用(Struts類對象)

  1. 首先解析struts.xml配置文件,其中有一個execute(String actionName,Map parameters)方法;
  2. 然后根據(jù)actionName找到對應的類class,反射實例化Action對象,調用setter方法設置該對象參數(shù)parameters
  3. 第三步反射執(zhí)行Action對象的execute獲取返回值;第四步通過Action對象getter返回參數(shù),
  4. 最后返回View視圖對象。

現(xiàn)在就以第一步——解析struts.xml為例,進行測試驅動開發(fā)。因為struts.xml文件如下

<?xml version="1.0" encoding="UTF-8"?>
<struts>
    <action name="login" class="com.coderising.litestruts.LoginAction">
        <result name="success">/jsp/homepage.jsp</result>
        <result name="fail">/jsp/showLogin.jsp</result>
    </action>
    <action name="logout" class="com.coderising.litestruts.LogoutAction">
        <result name="success">/jsp/welcome.jsp</result>
        <result name="error">/jsp/error.jsp</result>
    </action>
</struts>

我們需要根據(jù)execute(String actionName,Map parameters)方法的actionName,來解析xml文件,獲取對應的類名。因此,先編寫測試類

package com.coderising.litestruts;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class ConfigurationTest {
    Configuration cfg = new Configuration("struts.xml");

    @Test
    public void testGetClassName() {
        
        String clzName = cfg.getClassName("login");
        Assert.assertEquals("com.coderising.litestruts.LoginAction", clzName);
        
        
        clzName = cfg.getClassName("logout");
        Assert.assertEquals("com.coderising.litestruts.LogoutAction", clzName);
    }
}

其中,Configure對應于xml解析結果。ConfigurationTest對應測試類。從測試類中可以看出,我們銅鼓哦調用Configure的對象,調用其getClassName方法,傳入login參數(shù),來獲取我們希望的類名,最后進行斷言,判斷類名是否正確,這就是簡單的測試用例開發(fā)。
然后,我們開始開發(fā)解析結果Struts.xml類的開發(fā)(所需功能)。

package com.coderising.litestruts;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

public class Configuration {
    Map<String,ActionConfig> actions = new HashMap<>();
    public Configuration(String fileName) {     
        String packageName = this.getClass().getPackage().getName();
        packageName = packageName.replace('.', '/');
        InputStream is = this.getClass().getResourceAsStream("/" + packageName + "/" + fileName);
        parseXML(is);
        try {
            is.close();
        } catch (IOException e) {           
            throw new ConfigurationException(e);
        }
    }
    
    private void parseXML(InputStream is){
         SAXBuilder builder = new SAXBuilder();
         try {
            Document doc = builder.build(is);
            Element root = doc.getRootElement();
            for(Element actionElement : root.getChildren("action")){
                String actionName = actionElement.getAttributeValue("name");
                String clzName = actionElement.getAttributeValue("class");
                ActionConfig ac = new ActionConfig(actionName, clzName);
                for(Element resultElement : actionElement.getChildren("result")){
                    String resultName = resultElement.getAttributeValue("name");
                    String viewName = resultElement.getText().trim();
                    ac.addViewResult(resultName, viewName);
                }
                this.actions.put(actionName, ac);
            }
        } catch (JDOMException e) {
            throw new ConfigurationException(e);
        } catch (IOException e) {
            throw new ConfigurationException(e);
        }
    }

    public String getClassName(String action) {
        ActionConfig ac = this.actions.get(action);
        if(ac == null){
            return null;
        }
        return ac.getClassName();
    }
}

這里,使用jDom2來解析我們的struts.xml文件,用一個map結合actions儲存我們的結果。這樣編寫實現(xiàn)功能之后,我們就可以開始測試我們的功能代碼是否正確。于是,回到ConfigurationTest類,我們進行JUnit單元測試,測試通過。如果,發(fā)現(xiàn)有可以重構的代碼,我們可以進行重構簡化。
在完成該作業(yè)的過程中,可以按照這種TDD的思路進行功能開發(fā)。這樣做,有好處:

  1. 可以有效的避免過度設計帶來的浪費。
  2. 開發(fā)者在開發(fā)中擁有更全面的視角。
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容