JUnitReportReporter.java revision 3c331730b067c4367825ba373dbcf0be02df6fe5
11df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustpackage org.testng.reporters;
21df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
31df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.IReporter;
41df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.ISuite;
51df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.ISuiteResult;
61df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.ITestContext;
71df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.ITestResult;
81df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.collections.Lists;
91df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.collections.Maps;
101df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.internal.Utils;
111df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.internal.annotations.Sets;
121df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.xml.XmlSuite;
131df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
1406adacf0626ec131a81c342d2787bb5019ff5669Cédric Beustimport java.io.File;
15ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beustimport java.io.PrintWriter;
16ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beustimport java.io.StringWriter;
171df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.net.InetAddress;
181df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.net.UnknownHostException;
191df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.Calendar;
201df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.Date;
211df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.List;
221df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.Map;
231df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.Properties;
241df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.Set;
251df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
261df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustpublic class JUnitReportReporter implements IReporter {
271df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
281df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust  @Override
291df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust  public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites,
3006adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust      String defaultOutputDirectory) {
311df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
3206adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust    String outputDirectory = defaultOutputDirectory + File.separator + "junitreports";
331df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    Map<Class<?>, Set<ITestResult>> results = Maps.newHashMap();
343c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust    Map<Class<?>, Set<ITestResult>> failedConfigurations = Maps.newHashMap();
351df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    for (ISuite suite : suites) {
361df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      Map<String, ISuiteResult> suiteResults = suite.getResults();
371df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      for (ISuiteResult sr : suiteResults.values()) {
381df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        ITestContext tc = sr.getTestContext();
391df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        addResults(tc.getPassedTests().getAllResults(), results);
401df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        addResults(tc.getFailedTests().getAllResults(), results);
411df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        addResults(tc.getSkippedTests().getAllResults(), results);
423c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust        addResults(tc.getFailedConfigurations().getAllResults(), failedConfigurations);
431df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      }
441df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    }
451df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
461df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    for (Map.Entry<Class<?>, Set<ITestResult>> entry : results.entrySet()) {
471df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      Class<?> cls = entry.getKey();
481df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      Properties p1 = new Properties();
491df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      p1.setProperty("name", cls.getName());
501df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      Date timeStamp = Calendar.getInstance().getTime();
511df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      p1.setProperty(XMLConstants.ATTR_TIMESTAMP, timeStamp.toGMTString());
521df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
53ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust      List<TestTag> testCases = Lists.newArrayList();
541df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      int failures = 0;
55ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust      int errors = 0;
567a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust      int testCount = 0;
577a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust      int totalTime = 0;
581df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
591df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      for (ITestResult tr: entry.getValue()) {
60ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        TestTag testTag = new TestTag();
61ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust
621df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        if (tr.getStatus() != ITestResult.SUCCESS) failures++;
631df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        Properties p2 = new Properties();
641df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        p2.setProperty("classname", tr.getMethod().getMethod().getDeclaringClass().getName());
651df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        p2.setProperty("name", tr.getMethod().getMethodName());
667a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust        long time = tr.getEndMillis() - tr.getStartMillis();
677a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust        p2.setProperty("time", "" + time);
683c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust        Throwable t = getThrowable(tr, failedConfigurations);
69ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        if (t != null) {
70ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          t.fillInStackTrace();
71ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          StringWriter sw = new StringWriter();
72ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          PrintWriter pw = new PrintWriter(sw);
73ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          t.printStackTrace(pw);
74ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          testTag.message = t.getMessage();
75ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          testTag.type = t.getClass().getName();
76ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          testTag.stackTrace = sw.toString();
77ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          errors++;
78ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        }
797a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust        totalTime += time;
807a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust        testCount++;
81ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        testTag.properties = p2;
82ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        testCases.add(testTag);
831df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      }
841df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
851df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      p1.setProperty("failures", "" + failures);
86ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust      p1.setProperty("errors", "" + errors);
871df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      p1.setProperty("name", cls.getName());
887a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust      p1.setProperty("tests", "" + testCount);
897a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust      p1.setProperty("time", "" + totalTime);
901df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      try {
911df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        p1.setProperty(XMLConstants.ATTR_HOSTNAME, InetAddress.getLocalHost().getHostName());
921df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      } catch (UnknownHostException e) {
931df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        // ignore
941df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      }
951df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
961df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      //
971df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      // Now that we have all the information we need, generate the file
981df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      //
9906adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust      XMLStringBuffer xsb = new XMLStringBuffer("");
10006adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust      xsb.setXmlDetails("1.0", "UTF-8");
10106adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust      xsb.addComment("Generated by " + getClass().getName());
10206adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust
1031df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      xsb.push("testsuite", p1);
104ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust      for (TestTag testTag : testCases) {
105ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        if (testTag.stackTrace == null) xsb.addEmptyElement("testcase", testTag.properties);
106ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        else {
107ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          xsb.push("testcase", testTag.properties);
108ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust
109ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          Properties p = new Properties();
110d0df5e66f8b809f6d4c0fd6b77f70a2081508394Cédric Beust          if (testTag.message != null) p.setProperty("message", testTag.message);
111ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          p.setProperty("type", testTag.type);
112ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          xsb.push("error", p);
113ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          xsb.addCDATA(testTag.stackTrace);
114ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          xsb.pop("error");
115ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust
116ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          xsb.pop("testcase");
117ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        }
1181df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      }
1191df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      xsb.pop("testsuite");
12006adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust
12106adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust      String fileName = "TEST-" + cls.getName() + ".xml";
12206adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust      Utils.writeFile(outputDirectory, fileName, xsb.toXML());
1231df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    }
1241df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
1251df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust//    System.out.println(xsb.toXML());
1261df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust//    System.out.println("");
1271df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
1281df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust  }
1291df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
1303c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust  private Throwable getThrowable(ITestResult tr,
1313c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust      Map<Class<?>, Set<ITestResult>> failedConfigurations) {
1323c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust    Throwable result = tr.getThrowable();
1333c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust    if (result == null && tr.getStatus() == ITestResult.SKIP) {
1343c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust      // Attempt to grab the stack trace from the configuration failure
1353c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust      for (Set<ITestResult> failures : failedConfigurations.values()) {
1363c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust        for (ITestResult failure : failures) {
1373c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust          // Naive implementation for now, eventually, we need to try to find
1383c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust          // out if it's this failure that caused the skip since (maybe by
1393c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust          // seeing if the class of the configuration method is assignable to
1403c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust          // the class of the test method, although that's not 100% fool proof
1413c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust          if (failure.getThrowable() != null) return failure.getThrowable();
1423c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust        }
1433c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust      }
1443c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust    }
1453c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust
1463c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust    return result;
1473c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust  }
1483c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust
149ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust  class TestTag {
150ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust    public Properties properties;
151ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust    public String message;
152ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust    public String type;
153ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust    public String stackTrace;
154ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust  }
155ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust
1561df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust  private void addResults(Set<ITestResult> allResults, Map<Class<?>, Set<ITestResult>> out) {
1571df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    for (ITestResult tr : allResults) {
158ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust      Class<?> cls = tr.getMethod().getTestClass().getRealClass();
1591df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      Set<ITestResult> l = out.get(cls);
1601df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      if (l == null) {
1611df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        l = Sets.newHashSet();
1621df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        out.put(cls, l);
1631df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      }
1641df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      l.add(tr);
1651df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    }
1661df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust  }
1671df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
1681df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust}
169