Tony : Alex今天我们来做一个xml parser.我们使用的开发工具为Eclipse + JUnit
Alex : 好啊,喜欢接受挑战。
Tony : 先看看我们要解析的xml file的样子:

 
  
   
   
    
 

使用XmlSpy自动生成其DTD如下:

<!ATTLIST test 
 name CDATA #REQUIRED
>

<!ATTLIST suite 
 name CDATA #REQUIRED
 category CDATA #REQUIRED
>

<!ATTLIST classes 
 name CDATA #REQUIRED
>

我们就是要将该xml文件中的test , suite, class标签中存储的信息读出来,存储在数据结构中XmlTest中。所以我们的Parser的parse方法返回的就是个XmlTest的引用。我们通过上面的xml文件,我们可以确定一个类-XmlTest,带有一个成员name,创建XmlTest, 这个so easy

public class XmlTest {
    private String name;
   
    /**
     * @param name The name to set.
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return Returns the name.
     */
    public String getName() {
        return name;
    }
   
}

接下来,tdd的经典流程就是先写出feature list,来我们琢磨一下吧,

Alex :首先我们要知道我们要解析的xml文件的存放处,如果用户提供一个错误的位置,我们应该抛出异常。—-(1)

Tony :Great idea! 那我们就动手把。首先我们创建一个测试类ParserTest,添加一个方法

testNotFoundXmlFile,并创建一个Parser实例,将错误的xml文件路径传给它。代码如下:
public class ParserTest extends TestCase {
    public void testNotFindXmlFile(){
        try{
            Parser parser = new Parser("D:\\TestDemo\\demo1.xml");
            XmlTest result = parser.parse();
            fail("The FileNotFileFoundException should be raised!");
        }catch(FileNotFoundException fnfe){
           
        }
    }
}

run the test –> red bar
由于Parser类暂不存在,当然测试通过不了了。添加Parser类,并添加parse方法
public class Parser {
    private String xmlFilePath;
    public Parser(String xmlFilePath){
        this.xmlFilePath = xmlFilePath;
    }
   
    public XmlTest parse() {
        return null;
    }
}

run the test–>red bar

Alex :我来修改一下parse方法
public XmlTest parse()throws FileNotFoundException{
        File file = new File(xmlFilePath);
        if(!file.exists()){
            throw new FileNotFoundException();
        }
        return null;
    }
再试试吧。

Tony : Ok,green bar ,so beautiful!!! 我们这么快就完成了第一个feature了。
Alex : 是呀,不过这只是个开头。最主要的功能还没有实现呢。Just go on!

Tony : ok ,继续。

Alex :从dtd可以看出,该xml的根元素是test标签。下一步我们要完成的就是读取根元素test标签的属性信息—-(2)

Tony :i could not agree with you any more !! 这样就涉及到一些xml解析的知识了,我们来学习一下吧。

a short break !
Tony and Alex are studying JAXP together!

Tony :怎么样,ok了么
Alex :差不多了,JAXP不难,我们继续把。
Tony :是呀,按照JAXP给的例子,我们可能很容易就达到目的。ok,让我们add a new test.

public void testReadTestNode(){
        try{
            Parser parser = new Parser("D:\\TestDemo\\demo.xml");
            XmlTest result = parser.parse();         
            assertEquals("my first test", result.getName());
        }catch(FileNotFoundException fnfe){
            fail("The program should not reach here");
        }
}

run the test, as we expect it is a red bar.

Alex :根据JAXP的例子,我们解析特殊的xml file需要自己定制一个DefaultHandler的子类。然后将之传给SAXParser的parse方法。

Tony :好吧,让我们创建一个MyHandler class吧!

Alex :根据SAX的解析流程,我们要override some methods

Tony :要让我们的测试用例通过,我们得override DefaultHandler的startElement method,通过MyHandler获取我们所要的内容。

public class MyHandler extends DefaultHandler {

    private XmlTest curXmlTest = null;
   
    public XmlTest getXmlTest(){
        return curXmlTest;
    }
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        if ("test".equals(qName)) {
            curXmlTest = new XmlTest();
            curXmlTest.setName(attributes.getValue("name"));
        }
    }   
}

Alex :同时我们还要修改一下我们的Parser类的parse方法,如下:
parser.parse(file, myHandler);
result = myHandler.getXmlTest();
这样我们通过MyHandler取得了我们需要的东西,相信这一回test一定会通过的

Tony : 如你所愿,通过了。

Alex : 看看我们的代码,有些乱是吧。我们来重构一下吧。

Tony :我们先来重构一下测试代码。利用Junit提供的setUp将testfixture部分封装起来。

Alex :我来做。

public class ParserTest extends TestCase {

    private Parser parser;
   
    protected void setUp() throws Exception {       
        super.setUp();
        parser = new Parser("D:\\TestDemo\\demo.xml");
    }
   
    //…

   public void testReadTestNode(){
        try{           
            XmlTest result = parser.parse();         
            assertEquals("my first test", result.getName());
        }catch(FileNotFoundException fnfe){
            fail("The program should not reach here");
        }
    }
}
运行一下测试,一切Ok.还是那条令人兴奋的green bar

Tony : 以应用代码作为基础的的测试代码重构做完了,这两部分互相保证还是让我们很是放心的。

Alex :是呀,要不继续。我们来想想下一个todo item。你觉得我们是不是该读取suite标签信息了亚?———-(3)

Tony :就按你所说我们继续添加测试用例testReadSuiteNode, 我们修改一下XmlTest使之存储Suite信息。

Alex :那我们再创建一个类XmlSuite,然后在XmlTest中包含XmlSuite的集合。

Tony : 那我们的testReadSuiteNode可以这样写
public void testReadSuiteNode() {
        try {
            XmlTest result = parser.parse();
            assertEquals(1, result.getXmlSuites().size());
            assertEquals("test1", result.getXmlSuites().get(0).getName());
            assertEquals("unit", result.getXmlSuites().get(0).getCategory());
        } catch (FileNotFoundException fnfe) {
            fail("The program should not reach here");
        }
}

Alex : 我们需要添加XmlSuite类,还要改写XmlTest

Tony :我们在XmlTest中用一个ArrayList来存储XmlSuite。并提供get和add suite方法

Alex :我完成了,我们运行一下吧。green bar ,ok, let us have a short break!

© 2005, bigwhite. 版权所有.

Related posts:

  1. 如何编写类中的setter和getter
  2. Effective Java阅读笔记-item16
  3. 再谈Mock Object
  4. 开放与封闭
  5. Effective Java阅读笔记-item1