一个Xml Parser的TDD开发过程-Tony与Alex的对话系列
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!
评论