All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.testng.reporters.JUnitXMLReporter Maven / Gradle / Ivy
package org.testng.reporters;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.collections.Lists;
import org.testng.collections.Maps;
import org.testng.collections.Sets;
import org.testng.internal.IResultListener2;
import org.testng.internal.Utils;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.Collections;
import java.util.Collection;
import java.util.Queue;
import java.util.TimeZone;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.regex.Pattern;
import java.text.SimpleDateFormat;
/**
* A JUnit XML report generator (replacing the original JUnitXMLReporter that was
* based on XML APIs).
*
* @author Alex Popescu
*/
public class JUnitXMLReporter implements IResultListener2 {
private static final Pattern ENTITY= Pattern.compile("&[a-zA-Z]+;.*");
private static final Pattern LESS= Pattern.compile("<");
private static final Pattern GREATER= Pattern.compile(">");
private static final Pattern SINGLE_QUOTE = Pattern.compile("'");
private static final Pattern QUOTE = Pattern.compile("\"");
private static final Map ATTR_ESCAPES= Maps.newHashMap();
static {
ATTR_ESCAPES.put("<", LESS);
ATTR_ESCAPES.put(">", GREATER);
ATTR_ESCAPES.put("'", SINGLE_QUOTE);
ATTR_ESCAPES.put(""", QUOTE);
}
private int m_numFailed= 0;
private Queue m_allTests = new ConcurrentLinkedDeque<>();
private Queue m_configIssues = new ConcurrentLinkedDeque<>();
private Map m_fileNameMap = Maps.newHashMap();
private int m_fileNameIncrementer = 0;
@Override
public void onTestStart(ITestResult result) {
}
@Override
public void beforeConfiguration(ITestResult tr) {
}
/**
* Invoked each time a test succeeds.
*/
@Override
public void onTestSuccess(ITestResult tr) {
m_allTests.add(tr);
}
@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult tr) {
m_allTests.add(tr);
}
/**
* 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);
}
/**
* Invoked after the test class is instantiated and before
* any configuration method is called.
*
*/
@Override
public void onStart(ITestContext context) {
}
/**
* Invoked after all the tests have run and all their
* Configuration methods have been called.
*
*/
@Override
public void onFinish(ITestContext context) {
generateReport(context);
resetAll();
}
/**
* @see org.testng.IConfigurationListener#onConfigurationFailure(org.testng.ITestResult)
*/
@Override
public void onConfigurationFailure(ITestResult itr) {
m_configIssues.add(itr);
}
/**
* @see org.testng.IConfigurationListener#onConfigurationSkip(org.testng.ITestResult)
*/
@Override
public void onConfigurationSkip(ITestResult itr) {
m_configIssues.add(itr);
}
/**
* @see org.testng.IConfigurationListener#onConfigurationSuccess(org.testng.ITestResult)
*/
@Override
public void onConfigurationSuccess(ITestResult itr) {
}
/**
* generate the XML report given what we know from all the test results
*/
protected void generateReport(ITestContext context) {
XMLStringBuffer document= new XMLStringBuffer();
document.addComment("Generated by " + getClass().getName());
Properties attrs= new Properties();
attrs.setProperty(XMLConstants.ATTR_ERRORS, "0");
attrs.setProperty(XMLConstants.ATTR_FAILURES, Integer.toString(m_numFailed));
attrs.setProperty(XMLConstants.ATTR_IGNORED, Integer.toString(context.getExcludedMethods().size()));
try {
attrs.setProperty(XMLConstants.ATTR_HOSTNAME, InetAddress.getLocalHost().getHostName());
} catch (UnknownHostException e) {
// ignore
}
Set packages = getPackages(context);
if (packages.size() > 0) {
attrs.setProperty(XMLConstants.ATTR_NAME, context.getCurrentXmlTest().getName());
// attrs.setProperty(XMLConstants.ATTR_PACKAGE, packages.iterator().next());
}
attrs.setProperty(XMLConstants.ATTR_TESTS, Integer.toString(m_allTests.size()));
attrs.setProperty(XMLConstants.ATTR_TIME,
Double.toString((context.getEndDate().getTime() - context.getStartDate().getTime()) / 1000.0));
attrs.setProperty(XMLConstants.ATTR_TIMESTAMP, timeAsGmt());
document.push(XMLConstants.TESTSUITE, attrs);
createElementFromTestResults(document, m_configIssues);
createElementFromTestResults(document, m_allTests);
createElementFromIgnoredTests(document, context);
document.pop();
Utils.writeUtf8File(context.getOutputDirectory(),generateFileName(context) + ".xml", document.toXML());
}
static String timeAsGmt() {
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
sdf.applyPattern("dd MMM yyyy HH:mm:ss z");
return sdf.format(Calendar.getInstance().getTime());
}
private synchronized void createElementFromTestResults(XMLStringBuffer document, Collection results) {
for(ITestResult tr : results) {
createElement(document, tr);
}
}
private synchronized void createElementFromIgnoredTests(XMLStringBuffer doc, ITestContext context) {
Collection methods = context.getExcludedMethods();
for (ITestNGMethod method : methods) {
Properties properties = getPropertiesFor(method, 0);
doc.push(XMLConstants.TESTCASE,properties);
doc.addEmptyElement(XMLConstants.ATTR_IGNORED);
doc.pop();
}
}
private Properties getPropertiesFor(ITestNGMethod method, long elapsedTimeMillis) {
Properties attrs= new Properties();
String name= Utils.detailedMethodName(method, false);
attrs.setProperty(XMLConstants.ATTR_NAME, name);
attrs.setProperty(XMLConstants.ATTR_CLASSNAME, method.getRealClass().getName());
attrs.setProperty(XMLConstants.ATTR_TIME, Double.toString(((double) elapsedTimeMillis) / 1000));
return attrs;
}
private Set getPackages(ITestContext context) {
Set result = Sets.newHashSet();
for (ITestNGMethod m : context.getAllTestMethods()) {
Package pkg = m.getConstructorOrMethod().getDeclaringClass().getPackage();
if (pkg != null) {
result.add(pkg.getName());
}
}
return result;
}
private void createElement(XMLStringBuffer doc, ITestResult tr) {
long elapsedTimeMillis= tr.getEndMillis() - tr.getStartMillis();
Properties attrs= getPropertiesFor(tr.getMethod(), elapsedTimeMillis);
if (tr.getMethod().isTest()) {
attrs.setProperty(XMLConstants.ATTR_NAME, tr.getName());
}
if((ITestResult.FAILURE == tr.getStatus()) || (ITestResult.SKIP == tr.getStatus())) {
doc.push(XMLConstants.TESTCASE, attrs);
if(ITestResult.FAILURE == tr.getStatus()) {
createFailureElement(doc, tr);
}
else if(ITestResult.SKIP == tr.getStatus()) {
createSkipElement(doc);
}
doc.pop();
}
else {
doc.addEmptyElement(XMLConstants.TESTCASE, attrs);
}
}
private void createFailureElement(XMLStringBuffer doc, ITestResult tr) {
Properties attrs= new Properties();
Throwable t= tr.getThrowable();
if(t != null) {
attrs.setProperty(XMLConstants.ATTR_TYPE, t.getClass().getName());
String message= t.getMessage();
if((message != null) && (message.length() > 0)) {
attrs.setProperty(XMLConstants.ATTR_MESSAGE, encodeAttr(message)); // ENCODE
}
doc.push(XMLConstants.FAILURE, attrs);
doc.addCDATA(Utils.shortStackTrace(t, false));
doc.pop();
}
else {
doc.addEmptyElement(XMLConstants.FAILURE); // THIS IS AN ERROR
}
}
private void createSkipElement(XMLStringBuffer doc) {
doc.addEmptyElement(XMLConstants.SKIPPED);
}
private String encodeAttr(String attr) {
String result= replaceAmpersand(attr, ENTITY);
for(Map.Entry e: ATTR_ESCAPES.entrySet()) {
result= e.getValue().matcher(result).replaceAll(e.getKey());
}
return result;
}
private String replaceAmpersand(String str, Pattern pattern) {
int start = 0;
int idx = str.indexOf('&', start);
if(idx == -1) {
return str;
}
StringBuilder result= new StringBuilder();
while(idx != -1) {
result.append(str.substring(start, idx));
if(pattern.matcher(str.substring(idx)).matches()) {
// do nothing it is an entity;
result.append("&");
}
else {
result.append("&");
}
start= idx + 1;
idx= str.indexOf('&', start);
}
result.append(str.substring(start));
return result.toString();
}
/**
* Reset all member variables for next test.
* */
private void resetAll() {
m_allTests = new ConcurrentLinkedDeque<>();
m_configIssues = new ConcurrentLinkedDeque<>();
m_numFailed = 0;
}
/**
* This method guarantees unique file names for reports.
* Also, this will guarantee that the old reports are overwritten when tests are run again.
*
* @param context
* test context
* @return unique name for the file associated with this test context.
* */
private String generateFileName(ITestContext context) {
String fileName;
String keyToSearch = context.getSuite().getName() + context.getName();
if (m_fileNameMap.get(keyToSearch) == null) {
fileName = context.getName();
} else {
fileName = context.getName() + m_fileNameIncrementer++;
}
m_fileNameMap.put(keyToSearch, fileName);
return fileName;
}
}