在java中编写测试用例的问题

时间:2011-01-20 07:25:02

标签: java

  

可能重复:
  how to write test case in java

喜     我创建了一个类,其中有一个构造函数,如下所示:

public class ABC {

            private static String host;
            private static String port;
            private static String browser;
            private static String url;
            private static String fullurl;

           public ABC(){
                try { 
                   File file = new File("Element.xml");
                      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                      DocumentBuilder db = dbf.newDocumentBuilder();
                      Document doc = db.parse(file);

doc.getDocumentElement()。normalize();

请告诉我构造函数的测试用例:

3 个答案:

答案 0 :(得分:1)

我不知道你需要什么样的测试用例。 但是,您可以通过以下方式验证最终结果:提供xml并声明有关host,port,browser,url,fullurl的值。

也许您需要重构它以通过测试用例创建xml文本或文件集。

答案 1 :(得分:1)

首先,doc不是输出。它是构造函数中的局部变量,无法在单元测试中进行测试/验证。但另一方面,您可以依赖(经过测试的)Parser。它将为给定的输入文件生成正确的DOM。

如果输入文件中的值存储到指定的字段中,您可能需要测试。

因此,创建一个包含合法值的输入文件,创建一个实例并断言字段是否包含正确的值:

 @Test
 public void testABCWithLegalValues() {
    ABC abc = new ABC("correct.xml");  // NOTE! I invented a new constructor
                                       //  to allow passing test config files!!
    assertEquals("www.google.com", abc.getHost());
    assertEquals(80, abc.getPort());
    // ...
 }

这是基于jUnit 4的示例测试方法。

其他测试会向构造函数提供格式错误的xml文件或包含非法数据的文件(如端口地址> 65535),并验证该类是否按指定做出反应。

答案 2 :(得分:1)

您的班级正在执行两项不同的任务:

  1. 读取文件并将其解析为文档
  2. 处理文档以确定主机,端口,浏览器,网址和完整
  3. 由于目前这一切都发生在构造函数中,并且文件名是硬编码的,因此这个类很难进行单元测试。

    如果你可以修改课程,那么我的建议就是让这个课程可以测试:

    不要硬编码要解析的文件的名称。我会在这里将它作为构造函数参数传递,因为您以后不需要fileName,因此无需将其保留为私有字段。

    分离任务,让构造函数读取文件并创建一个单独的方法来处理文档。

    由于您需要codez,因此这里是修改后的类:

    import java.io.File;
    import java.io.IOException;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    
    import org.apache.log4j.Logger;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    import org.xml.sax.SAXException;
    
    public class ABC {
    
        private static final Logger LOG = Logger.getLogger(ABC.class);
        private static final String DEFAULT_FILENAME = "Element.xml";
        private String host;
        private String port;
        private String browser;
        private String url;
        private String fullurl;
    
        public class AbcFileAccessException extends Exception {
            private static final long serialVersionUID = 1L;
    
            public AbcFileAccessException(Exception e) {
                super(e);
            }
        }
    
        public ABC() throws AbcFileAccessException {
            this(DEFAULT_FILENAME);
        }
    
        public ABC(String fileName) throws AbcFileAccessException {
            File file = new File(fileName);
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            try {
                DocumentBuilder db = dbf.newDocumentBuilder();
                process(db.parse(file));
            } catch (ParserConfigurationException e) {
                throw new AbcFileAccessException(e);
            } catch (SAXException e) {
                throw new AbcFileAccessException(e);
            } catch (IOException e) {
                throw new AbcFileAccessException(e);
            }
        }
    
        public ABC(Document document) {
            process(document);
        }
    
        public void process(Document document) {
    
            if (document == null) {
                throw new IllegalArgumentException("Document may not be null");
            }
            document.getDocumentElement().normalize();
            LOG.info("Root element " + document.getDocumentElement().getNodeName());
            NodeList nodeLst = document.getElementsByTagName("selenium");
    
            for (int s = 0; s < nodeLst.getLength(); s++) {
    
                Node fstNode = nodeLst.item(s);
    
                if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
    
                    Element fstElmnt = (Element) fstNode;
                    NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("name");
                    Element fstNmElmnt = (Element) fstNmElmntLst.item(0);
                    NodeList fstNm = fstNmElmnt.getChildNodes();
                    String name = ((Node) fstNm.item(0)).getNodeValue();
    
                    NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("value");
                    Element lstNmElmnt = (Element) lstNmElmntLst.item(0);
                    NodeList lstNm = lstNmElmnt.getChildNodes();
    
                    String value = ((Node) lstNm.item(0)).getNodeValue();
                    if (name.equals("host")) {
                        host = value;
                    }
                    if (name.equals("port")) {
                        port = value;
                    }
                    if (name.equals("browser")) {
                        browser = value;
                    }
                    if (name.equals("url")) {
                        url = value;
                    }
                    if (name.equals("fullurl")) {
                        fullurl = value;
                    }
                }
            }
        }
    
        public String getHost() {
            return host;
        }
    
        public String getPort() {
            return port;
        }
    
        public String getBrowser() {
            return browser;
        }
    
        public String getUrl() {
            return url;
        }
    
        public String getFullurl() {
            return fullurl;
        }
    }
    

    我做的其他改进:

    避免像这样运行时数据的静态字段。如果它们是私有的(如在您的示例中)那么它们可以只是实例字段,看到您已经在创建类的(非单例)实例。如果你打算让它们被其他类访问,那就更糟了,因为那些其他类可以访问像ABC.host这样的字段,这使得它们难以测试并锁定在你的实现类中。我们现在不要进入( - :

    永远不要从构造函数中调用setter(请参阅http://www.javapractices.com/topic/TopicAction.do?Id=215获取解释)。

    范围try-catch块尽可能窄(或实际)。这使得您的代码更具可读性,因为它可以清楚地抛出异常。

    分别捕获每个异常类型。将它们组合在一起会使代码的可读性降低。我同意这对API的某些部分来说是一种痛苦(尝试使用反射),但这是一种很好的做法。假设开发人员应该能够从打印输出中读取和理解您的代码(因此不需要IDE的悬停和代码导航功能)。

    不要通过调用printStacktrace来处理异常,记录错误或抛出RuntimeException(如果可以避免)。如果这样做,至少要彻底记录这些错误情况。可以为错误条件创建自己的异常类型,这使得API非常容易理解(因此其他开发人员不必深入研究您的代码,但可以在阅读JavaDoc后使用该类)。

    不要使用System.out.println进行日志记录,请使用Log4j之类的日志框架。

    现在可以按如下方式测试该类:

    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import javax.xml.transform.Result;
    import javax.xml.transform.Source;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerConfigurationException;
    import javax.xml.transform.TransformerException;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.TransformerFactoryConfigurationError;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;
    
    import junit.framework.Assert;
    
    import org.junit.Before;
    import org.junit.Test;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    
    import xcon.pilot.ABC.AbcFileAccessException;
    
    public class ABCTest {
    
        private Document document;
    
        @Before
        public void setUp() throws Exception {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            document = builder.newDocument();
        }
    
        @Test
        public void testProcess() throws ParserConfigurationException,
                AbcFileAccessException, TransformerFactoryConfigurationError,
                TransformerException {
    
            Element root = (Element) document.createElement("root");
            document.appendChild(root);
    
            String host = "myhost";
            String port = "myport";
            String browser = "mybrowser";
            String url = "myurl";
            String fullurl = "myfullurl";
    
            root.appendChild(createElement("host", host));
            root.appendChild(createElement("port", port));
            root.appendChild(createElement("browser", browser));
            root.appendChild(createElement("url", url));
            root.appendChild(createElement("fullurl", fullurl));
    
            // for your convenience
            printXml();
    
            ABC instance = new ABC(document);
    
            Assert.assertEquals(host, instance.getHost());
            Assert.assertEquals(port, instance.getPort());
            Assert.assertEquals(browser, instance.getBrowser());
            Assert.assertEquals(url, instance.getUrl());
            Assert.assertEquals(fullurl, instance.getFullurl());
        }
    
        private Element createElement(String name, String value) {
    
            Element result = (Element) document.createElement("selenium");
    
            Element nameElement = document.createElement("name");
            nameElement.setTextContent(name);
            result.appendChild(nameElement);
    
            Element valueElement = document.createElement("value");
            valueElement.setTextContent(value);
            result.appendChild(valueElement);
    
            return result;
    
        }
    
        private void printXml() throws TransformerConfigurationException,
                TransformerFactoryConfigurationError, TransformerException {
            Transformer transformer = TransformerFactory.newInstance()
                    .newTransformer();
            Source source = new DOMSource(document);
            Result output = new StreamResult(System.out);
            transformer.transform(source, output);
        }
    }
    

    这会测试您的文档处理逻辑。测试文件的读取和解析是非常棘手的,并不能真正被视为单元测试,因为您始终依赖于操作系统及其文件系统。我通常将其作为集成测试和构建/部署支持的一部分。它有助于在代码中建立良好的健全性检查和错误处理,从而清楚地及早地报告丢失/不正确的文件。

    希望这有助于你。