| package org.testng.reporters; |
| |
| |
| import org.testng.ITestContext; |
| import org.testng.ITestResult; |
| import org.testng.collections.Lists; |
| import org.testng.internal.IResultListener; |
| import org.testng.internal.Utils; |
| import org.w3c.dom.CDATASection; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| |
| import java.io.BufferedWriter; |
| import java.io.File; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.dom.DOMSource; |
| import javax.xml.transform.stream.StreamResult; |
| |
| /** |
| * this XML Reporter will produce XML format compatible with the XMLJUnitResultFormatter from ant |
| * this enables TestNG output to be processed by tools that already handle this format |
| * |
| * borrows heavily from ideas in org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter |
| * |
| * this is the original version which was replaced by JUnitXMLReporter |
| * @TODO: clean up |
| */ |
| public class JUnitXMLReporter2 implements IResultListener { |
| |
| private String m_outputFileName= null; |
| private File m_outputFile= null; |
| private ITestContext m_testContext= null; |
| |
| /** |
| * keep lists of all the results |
| */ |
| private int m_numPassed= 0; |
| private int m_numFailed= 0; |
| private int m_numSkipped= 0; |
| private int m_numFailedButIgnored= 0; |
| private List<ITestResult> m_allTests |
| = Collections.synchronizedList(Lists.<ITestResult>newArrayList()); |
| private List<ITestResult> m_configIssues |
| = Collections.synchronizedList(Lists.<ITestResult>newArrayList()); |
| |
| @Override |
| public void onTestStart(ITestResult result) { |
| } |
| |
| /** |
| * Invoked each time a test succeeds. |
| */ |
| @Override |
| public void onTestSuccess(ITestResult tr) { |
| m_allTests.add(tr); |
| m_numPassed++; |
| } |
| |
| @Override |
| public void onTestFailedButWithinSuccessPercentage(ITestResult tr) { |
| m_allTests.add(tr); |
| m_numFailedButIgnored++; |
| } |
| |
| /** |
| * Invoked each time a test fails. |
| */ |
| @Override |
| public void onTestFailure(ITestResult tr) { |
| m_allTests.add(tr); |
| m_numFailed++; |
| } |
| |
| /** |
| * Invoked each time a test is skipped. |
| */ |
| @Override |
| public void onTestSkipped(ITestResult tr) { |
| m_allTests.add(tr); |
| m_numSkipped++; |
| } |
| |
| /** |
| * Invoked after the test class is instantiated and before |
| * any configuration method is called. |
| * |
| */ |
| @Override |
| public void onStart(ITestContext context) { |
| m_outputFileName= context.getOutputDirectory() + File.separator + context.getName() + ".xml"; |
| m_outputFile= new File(m_outputFileName); |
| m_testContext= context; |
| } |
| |
| /** |
| * Invoked after all the tests have run and all their |
| * Configuration methods have been called. |
| * |
| */ |
| @Override |
| public void onFinish(ITestContext context) { |
| generateReport(); |
| } |
| |
| /** |
| * generate the XML report given what we know from all the test results |
| */ |
| protected void generateReport() { |
| try { |
| DocumentBuilderFactory docBuilderFactory= DocumentBuilderFactory.newInstance(); |
| docBuilderFactory.setNamespaceAware(true); // so we can transform it later |
| DocumentBuilder docBuilder= docBuilderFactory.newDocumentBuilder(); |
| Document d= docBuilder.newDocument(); |
| Element rootElement= d.createElement(XMLConstants.TESTSUITE); |
| rootElement.setAttribute(XMLConstants.ATTR_NAME, m_testContext.getName()); |
| |
| Element propsElement= d.createElement(XMLConstants.PROPERTIES); |
| rootElement.appendChild(propsElement); |
| |
| // properties. just TestNG properties or also System properties? |
| |
| rootElement.setAttribute(XMLConstants.ATTR_TESTS, "" + m_allTests.size()); |
| rootElement.setAttribute(XMLConstants.ATTR_FAILURES, "" + m_numFailed); |
| rootElement.setAttribute(XMLConstants.ATTR_ERRORS, "0"); // FIXME |
| |
| long elapsedTimeMillis= m_testContext.getEndDate().getTime() |
| - m_testContext.getStartDate().getTime(); |
| rootElement.setAttribute(XMLConstants.ATTR_TIME, "" + (elapsedTimeMillis / 1000.0)); |
| |
| for(ITestResult tr: m_configIssues) { |
| Element element= createElement(d, tr); |
| rootElement.appendChild(element); |
| } |
| for(ITestResult tr : m_allTests) { |
| Element testCaseElement= createElement(d, tr); |
| rootElement.appendChild(testCaseElement); |
| } |
| |
| BufferedWriter fw= new BufferedWriter(new FileWriter(m_outputFile)); |
| |
| Transformer transformer= TransformerFactory.newInstance().newTransformer(); |
| transformer.transform(new DOMSource(rootElement), new StreamResult(fw)); |
| fw.flush(); |
| fw.close(); |
| } |
| catch(IOException ioe) { |
| ioe.printStackTrace(); |
| System.err.println("failed to create JUnitXML because of " + ioe); |
| } |
| catch(ParserConfigurationException pce) { |
| pce.printStackTrace(); |
| System.err.println("failed to create JUnitXML because of " + pce); |
| } |
| catch(TransformerException te) { |
| te.printStackTrace(); |
| System.err.println("Error while writing out JUnitXML because of " + te); |
| } |
| } |
| |
| private Element createElement(Document doc, ITestResult tr) { |
| Element resultElement= doc.createElement(XMLConstants.TESTCASE); |
| long elapsedTimeMillis= tr.getEndMillis() - tr.getStartMillis(); |
| String name= tr.getMethod().isTest() ? tr.getName() : Utils.detailedMethodName(tr.getMethod(), false); |
| resultElement.setAttribute(XMLConstants.ATTR_NAME, name); |
| resultElement.setAttribute(XMLConstants.ATTR_CLASSNAME, |
| tr.getTestClass().getRealClass().getName()); |
| resultElement.setAttribute(XMLConstants.ATTR_TIME, |
| "" + ((double) elapsedTimeMillis)/1000); |
| if (ITestResult.FAILURE == tr.getStatus()) { |
| Element nested = createFailureElement(doc, tr); |
| resultElement.appendChild(nested); |
| } |
| else if (ITestResult.SKIP == tr.getStatus()) { |
| Element nested = createSkipElement(doc, tr); |
| resultElement.appendChild(nested); |
| } |
| |
| return resultElement; |
| } |
| |
| private Element createFailureElement(Document doc, ITestResult tr) { |
| Element nested= doc.createElement(XMLConstants.FAILURE); |
| Throwable t = tr.getThrowable(); |
| if (t != null) { |
| nested.setAttribute(XMLConstants.ATTR_TYPE, t.getClass().getName()); |
| String message = t.getMessage(); |
| if ((message != null) && (message.length() > 0)) { |
| nested.setAttribute(XMLConstants.ATTR_MESSAGE, message); |
| } |
| CDATASection trace= doc.createCDATASection(Utils.stackTrace(t, false)[0]); |
| nested.appendChild(trace); |
| } |
| |
| return nested; |
| } |
| |
| private Element createSkipElement(Document doc, ITestResult tr) { |
| return doc.createElement("skipped"); |
| } |
| |
| /** |
| * @see org.testng.internal.IConfigurationListener#onConfigurationFailure(org.testng.ITestResult) |
| */ |
| @Override |
| public void onConfigurationFailure(ITestResult itr) { |
| m_configIssues.add(itr); |
| } |
| |
| /** |
| * @see org.testng.internal.IConfigurationListener#onConfigurationSkip(org.testng.ITestResult) |
| */ |
| @Override |
| public void onConfigurationSkip(ITestResult itr) { |
| m_configIssues.add(itr); |
| } |
| |
| /** |
| * @see org.testng.internal.IConfigurationListener#onConfigurationSuccess(org.testng.ITestResult) |
| */ |
| @Override |
| public void onConfigurationSuccess(ITestResult itr) { |
| } |
| } |