测试驱动开发(TDD)

测试驱动开发(Test-driven development)在维基百科上的定义是一种软件开发过程中的应用方法,由极限编程中倡导,以其倡导先写测试程序,然后编码实现其功能得名。测试驱动开发始于20世纪90年代。测试驱动开发的目的是取得快速反馈并使用“illustrate the main line”方法来构建程序。简单来说,就是从用户的角度先编写测试用例,再实现功能代码,再进行重构和代码测试。

现在就以liteStruts为例,简要说明TDD开发的过程。liteStruts所要实现的功能是读取struts.xml,执行Action,例如用户需要登录(login),发出请求后,web应用(Struts类对象)

  1. 首先解析struts.xml配置文件,其中有一个execute(String actionName,Map parameters)方法;
  2. 然后根据actionName找到对应的类class,反射实例化Action对象,调用setter方法设置该对象参数parameters
  3. 第三步反射执行Action对象的execute获取返回值;第四步通过Action对象getter返回参数,
  4. 最后返回View视图对象。

现在就以第一步——解析struts.xml为例,进行测试驱动开发。因为struts.xml文件如下



    
        /jsp/homepage.jsp
        /jsp/showLogin.jsp
    
    
        /jsp/welcome.jsp
        /jsp/error.jsp
    

我们需要根据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参数,来获取我们希望的类名,最后进行断言,判断类名是否正确,这就是简单的测试用例开发。
然后,我们开始开发解析结果Struts.xml类的开发(所需功能)。

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 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储存我们的结果。这样编写实现功能之后,我们就可以开始测试我们的功能代码是否正确。于是,回到ConfigurationTest类,我们进行JUnit单元测试,测试通过。如果,发现有可以重构的代码,我们可以进行重构简化。
在完成该作业的过程中,可以按照这种TDD的思路进行功能开发。这样做,有好处:

  1. 可以有效的避免过度设计带来的浪费。
  2. 开发者在开发中拥有更全面的视角。

你可能感兴趣的:(测试驱动开发(TDD))