diff --git a/CHANGES.txt b/CHANGES.txt index 528ef47717..1e7262c56d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,6 +6,7 @@ TODO =========================================================================== 5.2 +Added: EmailableReported (from Paul Mendelson) Added: parallel can now be "methods" or "tests". Boolean version deprecated Added: TestNGAntTask now uses the @ syntax to invoke TestNG Added: Command line understands @ syntax diff --git a/bin/testng.bat b/bin/testng.bat index ffb7bd499e..8ea1edff95 100644 --- a/bin/testng.bat +++ b/bin/testng.bat @@ -1,7 +1,5 @@ -set ROOT=c:\java\TestNG -set VERSION=4.7beta -set JAR=%ROOT%\testng-%VERSION%-jdk15.jar;%ROOT%\test\test.jar - rem set JAR=%ROOT%\testng-%VERSION%-jdk15.jar;%ROOT%\test\build - rem set JAR=%ROOT%\testng-%VERSION%-jdk14.jar;%ROOT%\test-14\build - -java -ea -classpath %ROOT%\3rdparty\junit.jar;%JAVA_HOME%\lib\tools.jar;%JAR%;%CLASSPATH% org.testng.TestNG %1 %2 %3 %4 %5 %6 %7 %8 %9 +set ROOT=c:\java\TestNG +set JAR=%ROOT%\testng-5.2beta-jdk15.jar;%ROOT%\test\build + rem set JAR=%ROOT%\testng-4.5-jdk14.jar;%ROOT%\test-14\build + +java -ea -classpath %ROOT%\3rdparty\junit.jar;%JAVA_HOME%\lib\tools.jar;%JAR%;%CLASSPATH% org.testng.TestNG %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/master.bat b/master.bat deleted file mode 100644 index a4040d8284..0000000000 --- a/master.bat +++ /dev/null @@ -1 +0,0 @@ -testng -hostfile test\hosts.properties -d test\test-output %1 %2 %3 %4 %5 test\testng.xml \ No newline at end of file diff --git a/slave.bat b/slave.bat deleted file mode 100644 index 24d2fb1b50..0000000000 --- a/slave.bat +++ /dev/null @@ -1 +0,0 @@ -testng -d client-output -slave %1 %2 %3 diff --git a/src/main/org/testng/TestNG.java b/src/main/org/testng/TestNG.java index 45a10d59e7..c82071025f 100644 --- a/src/main/org/testng/TestNG.java +++ b/src/main/org/testng/TestNG.java @@ -36,6 +36,7 @@ import org.testng.remote.ConnectionInfo; import org.testng.remote.RemoteSuiteWorker; import org.testng.remote.RemoteTestWorker; +import org.testng.reporters.EmailableReporter; import org.testng.reporters.FailedReporter; import org.testng.reporters.SuiteHTMLReporter; import org.testng.xml.Parser; @@ -163,6 +164,7 @@ private void init(boolean useDefaultListeners) { if (useDefaultListeners) { m_reporters.add(new SuiteHTMLReporter()); m_reporters.add(new FailedReporter()); + m_reporters.add(new EmailableReporter()); m_outputDir = DEFAULT_OUTPUTDIR; } diff --git a/src/main/org/testng/reporters/EmailableReporter.java b/src/main/org/testng/reporters/EmailableReporter.java new file mode 100644 index 0000000000..967847975c --- /dev/null +++ b/src/main/org/testng/reporters/EmailableReporter.java @@ -0,0 +1,370 @@ +package org.testng.reporters; + +import org.testng.IReporter; +import org.testng.IResultMap; +import org.testng.ISuite; +import org.testng.ISuiteResult; +import org.testng.ITestContext; +import org.testng.ITestNGMethod; +import org.testng.ITestResult; +import org.testng.Reporter; + +import org.testng.log4testng.Logger; +import org.testng.xml.XmlSuite; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +/** + * Reported designed to render self-contained HTML top down view + * of a testing suite. + * + * @author Paul Mendelson + * @version $Revision: 3 $ + */ +public class EmailableReporter implements IReporter +{ + Logger logger=Logger.getLogger(EmailableReporter.class); + //~ Instance fields ------------------------------------------------------ + + private PrintWriter out; + int row; + + //~ Methods -------------------------------------------------------------- + + /** Creates summary of the run */ + public void generateReport( + List xml, + List suites, + String outdir) + { + try { + out=new PrintWriter(new FileWriter(new File(outdir,"emailable-report.html"))); + } catch(IOException e) { + logger.error("output file",e); + return; + } + startHtml(out); + for(ISuite suite : suites) { + summarize(suite); + out.println(""); + Map r=suite.getResults(); + for(ISuiteResult r2 : r.values()) { + resultSummary( + r2.getTestContext().getFailedTests(), + "failed"); + resultSummary( + r2.getTestContext().getPassedTests(), + "passed"); + resultDetail( + r2.getTestContext().getFailedTests(), + "failed"); + resultDetail( + r2.getTestContext().getPassedTests(), + "passed"); + } + } + out.println(""); + out.close(); + } + + /** + * @param tests + */ + private void resultSummary(IResultMap tests,String style) + { + if(tests.getAllResults().size()>0) { + tableStart(style); + out.println( + "Class" + +"Method# of
ScenariosTime
(Msecs)"); + int row=0; + StringBuffer buff=new StringBuffer(); + String lastc=""; + int mq=0; + int cq=0; + for(ITestNGMethod method : getMethodSet(tests)) { + row+=1; + String cname=method.getTestClass().getName(); + if(!cname.equalsIgnoreCase(lastc)) { + if(mq>0) { + cq+=1; + out.println( + ""+""+lastc+buff); + } + mq=0; + buff.setLength(0); + lastc=cname; + } + Set result_set=tests.getResults(method); + long end=Long.MIN_VALUE; + long start=Long.MAX_VALUE; + for(ITestResult ans : tests.getResults(method)) { + if(ans.getEndMillis()>end) { + end=ans.getEndMillis(); + } + if(ans.getStartMillis()1) { + buff.append(""); + } + buff.append( + ""+qualifiedName(method)+"" + +""+result_set.size()+"" + +(end-start)+""); + } + if(mq>0) { + row+=1; + out.println( + ""+""+lastc+buff); + } + out.println(""); + } + } + + private String qualifiedName(ITestNGMethod method) { + String addon=""; + if(method.getGroups().length>0 && ! "basic".equalsIgnoreCase(method.getGroups()[0])) { + addon=" ("+method.getGroups()[0]+")"; + } + return method.getMethodName()+addon; + } + + private void resultDetail(IResultMap tests,String style) + { + if(tests.getAllResults().size()>0) { + int row=0; + StringBuffer buff=new StringBuffer(); + for(ITestNGMethod method : getMethodSet(tests)) { + row+=1; + String cname=method.getTestClass().getName(); + out.println( + "

"+cname+":"+method.getMethodName() + +"

"); + // Set result_set=tests.getResults(method); + // long end=Long.MIN_VALUE; + // long start=Long.MAX_VALUE; + int rq=0; + Set result_set=tests.getResults(method); + for(ITestResult ans : result_set) { + rq+=1; + Object[] pset=ans.getParameters(); + if(pset.length>0) { + if(rq==1) { + tableStart("param"); + out.print(""); + for(int x=1; x<=pset.length; x++) { + out.print( + "Parameter #"+x + +""); + } + out.println(""); + } + out.print(""); + for(Object p : pset) { + out.println( + ""+p+""); + } + out.println(""); + if(rq==result_set.size()) { + out.println(""); + } + } + List msgs=Reporter.getOutput(ans); + if(msgs.size()>0) { + out.println("
"); + for(String line : msgs) { + out.println(line+"
"); + } + out.println("
"); + } + } + // mq+=1; + // if(mq>1) + // buff.append(""); + // buff.append(""+method.getMethodName()+"" + // +""+result_set.size()+"" + // +(end-start) + // +""); + // } + // if(mq>0) { + // row+=1; + // out.println("" + // +""+lastc+buff); + out.println("

back to summary

"); + } + + // out.println(""); + } + } + + /** + * @param tests + * @return + */ + private Collection getMethodSet(IResultMap tests) + { + Set r=new TreeSet(new TestSorter()); + r.addAll(tests.getAllMethods()); + return r; + } + + private void summarize(ISuite suite) + { + tableStart("param"); + Map r=suite.getResults(); + for(ISuiteResult r2 : r.values()) { + ITestContext overview=r2.getTestContext(); + tableRow( + "# of Tests passed", + getMethodSet(overview.getPassedTests()).size()); + tableRow( + "# of Scenarios passed", + overview.getPassedTests().size()); + tableRow( + "# failed", + overview.getFailedTests().size()); + tableRow( + "# skipped", + overview.getSkippedTests().size()); + NumberFormat formatter=new DecimalFormat("#,##0.0"); + tableRow( + "Total Time", + formatter.format( + (overview.getEndDate().getTime()-overview.getStartDate().getTime())/1000.) + +" seconds"); + tableRow( + "Included Groups", + overview.getIncludedGroups()); + tableRow( + "Excluded Groups", + overview.getExcludedGroups()); + } + out.println(""); + } + + /** + * + */ + private void tableStart(String cssclass) + { + out.println( + ""); + row=0; + } + + private void tableRow(String label,String val) + { + row+=1; + out.println( + ""); + } + + private void tableRow(String label,long val) + { + tableRow( + label, + String.valueOf(val)); + } + + private void tableRow(String label,String[] val) + { + StringBuffer b=new StringBuffer(); + for(String v : val) + b.append(v+" "); + tableRow( + label, + b.toString().trim()); + } + + private void startHtml(PrintWriter out) + { + out.println(""); + out.println(""); + out.println("TestNG: Unit Test"); + out.println(""); + out.println(""); + out.println(""); + } + + //~ Inner Classes -------------------------------------------------------- + + /** + * DOCUMENT ME! + * + * @author $author$ + * @version $Revision: 3 $ + * + * @param DOCUMENT ME! + */ + private class TestSorter implements Comparator + { + //~ Methods ------------------------------------------------------------- + + /** + * DOCUMENT ME! + * + * @param o1 DOCUMENT ME! + * @param o2 DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public int compare(Object o1,Object o2) + { + int r= + ((T)o1).getTestClass().getName() + .compareTo(((T)o2).getTestClass().getName()); + if(r==0) { + r=((T)o1).getMethodName().compareTo(((T)o2).getMethodName()); + } + return r; + } + } +} diff --git a/testng.bat b/testng.bat deleted file mode 100644 index 8ea1edff95..0000000000 --- a/testng.bat +++ /dev/null @@ -1,5 +0,0 @@ -set ROOT=c:\java\TestNG -set JAR=%ROOT%\testng-5.2beta-jdk15.jar;%ROOT%\test\build - rem set JAR=%ROOT%\testng-4.5-jdk14.jar;%ROOT%\test-14\build - -java -ea -classpath %ROOT%\3rdparty\junit.jar;%JAVA_HOME%\lib\tools.jar;%JAR%;%CLASSPATH% org.testng.TestNG %1 %2 %3 %4 %5 %6 %7 %8 %9
"+label + +""+val+"