issues with writing test case in java [duplicate]
Possible Duplicate:
how to write test case in java
hi I created one class in which I have one constructor as follows:
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.getDocu开发者_C百科mentElement().normalize();
please tell me test case for constructor:
First of all, doc
is not the output. It is a local variable inside the constructor and can't be tested/validated in a unit test. But on the other hand, you can rely on the (tested) Parser. It will produce the correct DOM for the given input file.
You may want to test, if the values from the input file are stored to the fields as specified.
So create an input file with legal values, create an instance and assert if the fields contain the correct values:
@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());
// ...
}
This is an example test method based on jUnit 4.
Other tests would feed the constructor with malformed xml files or files with illegal data (like a port Address > 65535) and verify that the class reacts as specified.
I have no idea what kinds of test case you need. However, your can verify the final result in this way: feeding the xml and asserting the values about host, port, browser, url, fullurl.
Maybe you need refactor it to make xml text or file set by test-case.
Your class is performing two distinct tasks:
- Reading a file and parsing it as a Document
- Processing the Document to determine host, port, browser, url and fullurl
Since this currently all occurs within the constructor and the file name is hardcoded, this class is pretty hard to unit test.
If you can modify the class, then here are my suggestions to make this class testable:
Don't hardcode the name of the file to be parsed. I would pass it as a constructor argument here because you don't need the fileName later on so no need to keep it as a private field.
Separate the tasks, let the constructor read the file and create a separate method to process the document.
Since you wanted the codez, here is the modified class:
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;
}
}
Other improvements I made :
Avoid static fields for runtime data like this. If they are private (as in your example) then they can just be instance field, seeing you are already creating a (non-singleton) instance of the class. If you intended them to be accessed by other classes it is even worse, because those other classes could access the fields like ABC.host
which makes them hard to test and locked in to you implementation class. Let's not go into that now (-:
NEVER call setters from a contructor (see http://www.javapractices.com/topic/TopicAction.do?Id=215 for an explanation).
Scope try-catch blocks as narrowly as possible (or practical). This makes your code more readable because it is clear where the exceptions are being thrown.
Catch each exception type separately. Bundeling them together makes the code less readable. I agree this is a pain for some parts of the API (try using reflection), but it is good practice. Assume a developer should be able to read and understand your code from a printout (so without hovering and code navigation features of your IDE).
Don't handle exceptions by calling printStacktrace, logging an error or throwing a RuntimeException if you can avoid it. If you do, at least document these error conditions thoroughly. It is ok to create your own exception types for error conditions, this makes for a very understandable API (so other developers don't have to delve into your code, but can use the class after reading the JavaDoc).
Don't use System.out.println for logging, use a logging framework like Log4j.
This class can now be tested as follows:
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);
}
}
This tests your Document processing logic. Testing the reading and parsing of files is notably tricky and can't really be seen as unit testing because you are always dependent on the operating system and its filesystem. I usually leave that as part of integration testing and build/deployment support. It helps to build good sanity checks and error handling in your code so missing/incorrect files are reported clearly and early.
Hope this helped you.
精彩评论