blob: 88c6d6b4ec254d064f7efb3072d52e627a2daa6d [file] [log] [blame]
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) {
}
}