首先看下 maven-surefire 通过testng拉起单测,执行异常的日志(有助于我们理解testng中调用关系):
java.lang.instrument.IllegalClassFormatException: Error while instrumenting class com/suning/gcps/newutils/invoice/InvoiceSendTypeEnum. at org.jacoco.agent.rt.internal_6da5971.CoverageTransformer.transform(CoverageTransformer.java:93) at sun.instrument.TransformerManager.transform(TransformerManager.java:188) at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:800) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) at java.net.URLClassLoader.access$100(URLClassLoader.java:71) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) at com.suning.gcps.newutils.invoice.InvoiceSendTypeEnumTest.test(InvoiceSendTypeEnumTest.java:12) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:100) at org.testng.internal.Invoker.invokeMethod(Invoker.java:646) at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:811) at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1129) at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129) at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112) at org.testng.TestRunner.privateRun(TestRunner.java:746) at org.testng.TestRunner.run(TestRunner.java:600) at org.testng.SuiteRunner.runTest(SuiteRunner.java:366) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:361) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:319) at org.testng.SuiteRunner.run(SuiteRunner.java:268) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1264) at org.testng.TestNG.runSuitesLocally(TestNG.java:1189) at org.testng.TestNG.runSuites(TestNG.java:1104) at org.testng.TestNG.run(TestNG.java:1076) at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:62) at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:141) at org.apache.maven.surefire.Surefire.run(Surefire.java:180) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:350) at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021) Caused by: java.io.IOException: Error while instrumenting class com/suning/gcps/newutils/invoice/InvoiceSendTypeEnum. at org.jacoco.agent.rt.internal_6da5971.core.instr.Instrumenter.instrumentError(Instrumenter.java:160) at org.jacoco.agent.rt.internal_6da5971.core.instr.Instrumenter.instrument(Instrumenter.java:111) at org.jacoco.agent.rt.internal_6da5971.CoverageTransformer.transform(CoverageTransformer.java:91) ... 46 more Caused by: java.lang.IllegalStateException: Class com/suning/gcps/newutils/invoice/InvoiceSendTypeEnum is already instrumented. at org.jacoco.agent.rt.internal_6da5971.core.internal.instr.InstrSupport.assertNotInstrumented(InstrSupport.java:89) at org.jacoco.agent.rt.internal_6da5971.core.internal.instr.ClassInstrumenter.visitField(ClassInstrumenter.java:55) at org.jacoco.agent.rt.internal_6da5971.asm.ClassVisitor.visitField(ClassVisitor.java:272) at org.jacoco.agent.rt.internal_6da5971.asm.ClassReader.readField(ClassReader.java:768) at org.jacoco.agent.rt.internal_6da5971.asm.ClassReader.accept(ClassReader.java:689) at org.jacoco.agent.rt.internal_6da5971.asm.ClassReader.accept(ClassReader.java:506) at org.jacoco.agent.rt.internal_6da5971.core.instr.Instrumenter.instrument(Instrumenter.java:84) at org.jacoco.agent.rt.internal_6da5971.core.instr.Instrumenter.instrument(Instrumenter.java:108) ... 47 more从日志可以看出surefire.testng中的run 方法调用 surefire.testng.TestNGDirectoryTestSuite中execute方法;execute调用TestNGExecutor run 方法。
接着调入testng中的方法,testNG.run -> runSuites -> runSutiesLocally -> runSuitesSequentially
-> SuiteRunnerWorker.run -> runSuites
-> SuiteRunner.run -> privateRun -> invokeTestMethods
->testng.internal.TestMethodWorker.run -> invokeTestMethods
->testng.internal.Invoker.invokeTestMethods -> invokeMethod
->testng.internal.MethodInvocationHelper.invokeMethod
先看testNG这个类:
/**
* Run TestNG.
*/
public void run() {
initializeSuitesAndJarFile();
initializeConfiguration();
initializeDefaultListeners();
initializeCommandLineSuites();
initializeCommandLineSuitesParams();
initializeCommandLineSuitesGroups();
sanityCheck();
List<ISuite> suiteRunners = null;
runExecutionListeners(true /* start */);
m_start = System.currentTimeMillis();
//
// Slave mode
//
if (m_slavefileName != null) {
SuiteSlave slave = new SuiteSlave( m_slavefileName, this );
slave.waitForSuites();
}
//
// Regular mode
//
else if (m_masterfileName == null) {
suiteRunners = runSuitesLocally();
}
//
// Master mode
//
else {
SuiteDispatcher dispatcher = new SuiteDispatcher(m_masterfileName);
suiteRunners = dispatcher.dispatch(getConfiguration(),
m_suites, getOutputDirectory(),
getTestListeners());
}
m_end = System.currentTimeMillis();
runExecutionListeners(false /* finish */);
if(null != suiteRunners) {
generateReports(suiteRunners);
}
if(!m_hasTests) {
setStatus(HAS_NO_TEST);
if (TestRunner.getVerbose() > 1) {
System.err.println("[TestNG] No tests found. Nothing was run");
usage();
}
}
}
/**
* This needs to be public for maven2, for now..At least
* until an alternative mechanism is found.
*/
public List<ISuite> runSuitesLocally() {
SuiteRunnerMap suiteRunnerMap = new SuiteRunnerMap();
if (m_suites.size() > 0) {
if (m_suites.get(0).getVerbose() >= 2) {
Version.displayBanner();
}
// First initialize the suite runners to ensure there are no configuration issues.
// Create a map with XmlSuite as key and corresponding SuiteRunner as value
for (XmlSuite xmlSuite : m_suites) {
createSuiteRunners(suiteRunnerMap, xmlSuite);
}
//
// Run suites
//
if (m_suiteThreadPoolSize == 1 && !m_randomizeSuites) {
// Single threaded and not randomized: run the suites in order
for (XmlSuite xmlSuite : m_suites) {
runSuitesSequentially(xmlSuite, suiteRunnerMap, getVerbose(xmlSuite),
getDefaultSuiteName());
}
} else {
// Multithreaded: generate a dynamic graph that stores the suite hierarchy. This is then
// used to run related suites in specific order. Parent suites are run only
// once all the child suites have completed execution
DynamicGraph<ISuite> suiteGraph = new DynamicGraph<ISuite>();
for (XmlSuite xmlSuite : m_suites) {
populateSuiteGraph(suiteGraph, suiteRunnerMap, xmlSuite);
}
IThreadWorkerFactory<ISuite> factory = new SuiteWorkerFactory(suiteRunnerMap,
0 /* verbose hasn't been set yet */, getDefaultSuiteName());
GraphThreadPoolExecutor<ISuite> pooledExecutor =
new GraphThreadPoolExecutor<ISuite>(suiteGraph, factory, m_suiteThreadPoolSize,
m_suiteThreadPoolSize, Integer.MAX_VALUE, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
Utils.log("TestNG", 2, "Starting executor for all suites");
// Run all suites in parallel
pooledExecutor.run();
try {
pooledExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
pooledExecutor.shutdownNow();
}
catch (InterruptedException handled) {
Thread.currentThread().interrupt();
error("Error waiting for concurrent executors to finish " + handled.getMessage());
}
}
}
else {
setStatus(HAS_NO_TEST);
error("No test suite found. Nothing to run");
usage();
}
//
// Generate the suites report
//
return Lists.newArrayList(suiteRunnerMap.values());
}
private void runSuitesSequentially(XmlSuite xmlSuite,
SuiteRunnerMap suiteRunnerMap, int verbose, String defaultSuiteName) {
for (XmlSuite childSuite : xmlSuite.getChildSuites()) {
runSuitesSequentially(childSuite, suiteRunnerMap, verbose, defaultSuiteName);
}
SuiteRunnerWorker srw = new SuiteRunnerWorker(suiteRunnerMap.get(xmlSuite), suiteRunnerMap,
verbose, defaultSuiteName);
srw.run();
}
/**
* Populates the dynamic graph with the reverse hierarchy of suites. Edges are
* added pointing from child suite runners to parent suite runners, hence making
* parent suite runners dependent on all the child suite runners
*
* @param suiteGraph dynamic graph representing the reverse hierarchy of SuiteRunners
* @param suiteRunnerMap Map with XMLSuite as key and its respective SuiteRunner as value
* @param xmlSuite XML Suite
*/
private void populateSuiteGraph(DynamicGraph<ISuite> suiteGraph /* OUT */,
SuiteRunnerMap suiteRunnerMap, XmlSuite xmlSuite) {
ISuite parentSuiteRunner = suiteRunnerMap.get(xmlSuite);
if (xmlSuite.getChildSuites().isEmpty()) {
suiteGraph.addNode(parentSuiteRunner);
}
else {
for (XmlSuite childSuite : xmlSuite.getChildSuites()) {
suiteGraph.addEdge(parentSuiteRunner, suiteRunnerMap.get(childSuite));
populateSuiteGraph(suiteGraph, suiteRunnerMap, childSuite);
}
}
}
private void createSuiteRunners(SuiteRunnerMap suiteRunnerMap /* OUT */, XmlSuite xmlSuite) {
if (null != m_isJUnit && ! m_isJUnit.equals(XmlSuite.DEFAULT_JUNIT)) {
xmlSuite.setJUnit(m_isJUnit);
}
// If the skip flag was invoked on the command line, it
// takes precedence
if (null != m_skipFailedInvocationCounts) {
xmlSuite.setSkipFailedInvocationCounts(m_skipFailedInvocationCounts);
}
// Override the XmlSuite verbose value with the one from TestNG
if (m_verbose != null) {
xmlSuite.setVerbose(m_verbose);
}
if (null != m_configFailurePolicy) {
xmlSuite.setConfigFailurePolicy(m_configFailurePolicy);
}
for (XmlTest t : xmlSuite.getTests()) {
for (Map.Entry<String, Integer> ms : m_methodDescriptors.entrySet()) {
XmlMethodSelector xms = new XmlMethodSelector();
xms.setName(ms.getKey());
xms.setPriority(ms.getValue());
t.getMethodSelectors().add(xms);
}
}
suiteRunnerMap.put(xmlSuite, createSuiteRunner(xmlSuite));
for (XmlSuite childSuite : xmlSuite.getChildSuites()) {
createSuiteRunners(suiteRunnerMap, childSuite);
}
}
/**
* Creates a suite runner and configures its initial state
* @param xmlSuite
* @return returns the newly created suite runner
*/
private SuiteRunner createSuiteRunner(XmlSuite xmlSuite) {
SuiteRunner result = new SuiteRunner(getConfiguration(), xmlSuite,
m_outputDir,
m_testRunnerFactory,
m_useDefaultListeners,
m_methodInterceptor,
m_invokedMethodListeners,
m_testListeners);
for (ISuiteListener isl : m_suiteListeners) {
result.addListener(isl);
}
for (IReporter r : result.getReporters()) {
addListener(r);
}
for (IConfigurationListener cl : m_configuration.getConfigurationListeners()) {
result.addConfigurationListener(cl);
}
return result;
}
public static void main(String[] argv) {
TestNG testng = privateMain(argv, null);
System.exit(testng.getStatus());
}
/**
* <B>Note</B>: this method is not part of the public API and is meant for internal usage only.
*/
public static TestNG privateMain(String[] argv, ITestListener listener) {
TestNG result = new TestNG();
if (null != listener) {
result.addListener(listener);
}
//
// Parse the arguments
//
try {
CommandLineArgs cla = new CommandLineArgs();
m_jCommander = new JCommander(cla, argv);
validateCommandLineParameters(cla);
result.configure(cla);
}
catch(ParameterException ex) {
exitWithError(ex.getMessage());
}
//
// Run
//
try {
result.run();
}
catch(TestNGException ex) {
if (TestRunner.getVerbose() > 1) {
ex.printStackTrace(System.out);
}
else {
error(ex.getMessage());
}
result.setStatus(HAS_FAILURE);
}
return result;
}
/**
* Configure the TestNG instance based on the command line parameters.
*/
protected void configure(CommandLineArgs cla) {
if (cla.verbose != null) {
setVerbose(cla.verbose);
}
setOutputDirectory(cla.outputDirectory);
String testClasses = cla.testClass;
if (null != testClasses) {
String[] strClasses = testClasses.split(",");
List<Class> classes = Lists.newArrayList();
for (String c : strClasses) {
classes.add(ClassHelper.fileToClass(c));
}
setTestClasses(classes.toArray(new Class[classes.size()]));
}
setOutputDirectory(cla.outputDirectory);
if (cla.testNames != null) {
setTestNames(Arrays.asList(cla.testNames.split(",")));
}
// List<String> testNgXml = (List<String>) cmdLineArgs.get(CommandLineArgs.SUITE_DEF);
// if (null != testNgXml) {
// setTestSuites(testNgXml);
// }
// Note: can't use a Boolean field here because we are allowing a boolean
// parameter with an arity of 1 ("-usedefaultlisteners false")
if (cla.useDefaultListeners != null) {
setUseDefaultListeners("true".equalsIgnoreCase(cla.useDefaultListeners));
}
setGroups(cla.groups);
setExcludedGroups(cla.excludedGroups);
setTestJar(cla.testJar);
setXmlPathInJar(cla.xmlPathInJar);
setJUnit(cla.junit);
setMixed(cla.mixed);
setMaster(cla.master);
setSlave(cla.slave);
setSkipFailedInvocationCounts(cla.skipFailedInvocationCounts);
if (cla.parallelMode != null) {
setParallel(cla.parallelMode);
}
if (cla.configFailurePolicy != null) {
setConfigFailurePolicy(cla.configFailurePolicy);
}
if (cla.threadCount != null) {
setThreadCount(cla.threadCount);
}
if (cla.dataProviderThreadCount != null) {
setDataProviderThreadCount(cla.dataProviderThreadCount);
}
if (cla.suiteName != null) {
setDefaultSuiteName(cla.suiteName);
}
if (cla.testName != null) {
setDefaultTestName(cla.testName);
}
if (cla.listener != null) {
String sep = ";";
if (cla.listener.indexOf(",") >= 0) {
sep = ",";
}
String[] strs = Utils.split(cla.listener, sep);
List<Class> classes = Lists.newArrayList();
for (String cls : strs) {
classes.add(ClassHelper.fileToClass(cls));
}
setListenerClasses(classes);
}
if (null != cla.methodSelectors) {
String[] strs = Utils.split(cla.methodSelectors, ",");
for (String cls : strs) {
String[] sel = Utils.split(cls, ":");
try {
if (sel.length == 2) {
addMethodSelector(sel[0], Integer.valueOf(sel[1]));
} else {
error("Method selector value was not in the format org.example.Selector:4");
}
}
catch (NumberFormatException nfe) {
error("Method selector value was not in the format org.example.Selector:4");
}
}
}
if (cla.objectFactory != null) {
setObjectFactory(ClassHelper.fileToClass(cla.objectFactory));
}
if (cla.testRunnerFactory != null) {
setTestRunnerFactoryClass(
ClassHelper.fileToClass(cla.testRunnerFactory));
}
if (cla.reporter != null) {
ReporterConfig reporterConfig = ReporterConfig.deserialize(cla.reporter);
addReporter(reporterConfig);
}
if (cla.commandLineMethods.size() > 0) {
m_commandLineMethods = cla.commandLineMethods;
}
if (cla.suiteFiles != null) {
setTestSuites(cla.suiteFiles);
}
setSuiteThreadPoolSize(cla.suiteThreadPoolSize);
setRandomizeSuites(cla.randomizeSuites);
}
public void setSuiteThreadPoolSize(Integer suiteThreadPoolSize) {
m_suiteThreadPoolSize = suiteThreadPoolSize;
}
public Integer getSuiteThreadPoolSize() {
return m_suiteThreadPoolSize;
}
public void setRandomizeSuites(boolean randomizeSuites) {
m_randomizeSuites = randomizeSuites;
}
SuiteRunnerWorker类:
public class SuiteRunnerWorker implements IWorker<ISuite> {
private SuiteRunner m_suiteRunner;
private Integer m_verbose;
private String m_defaultSuiteName;
private SuiteRunnerMap m_suiteRunnerMap;
public SuiteRunnerWorker(ISuite suiteRunner,
SuiteRunnerMap suiteRunnerMap,
int verbose,
String defaultSuiteName)
{
m_suiteRunnerMap = suiteRunnerMap;
m_suiteRunner = (SuiteRunner) suiteRunner;
m_verbose = verbose;
m_defaultSuiteName = defaultSuiteName;
}
/**
* Runs a suite
* @param suiteRunnerMap map of suiteRunners that are updated with test results
* @param xmlSuite XML suites to run
*/
private void runSuite(SuiteRunnerMap suiteRunnerMap /* OUT */, XmlSuite xmlSuite)
{
if (m_verbose > 0) {
StringBuffer allFiles = new StringBuffer();
allFiles.append(" ").append(xmlSuite.getFileName() != null
? xmlSuite.getFileName() : m_defaultSuiteName).append('\n');
Utils.log("TestNG", 0, "Running:\n" + allFiles.toString());
}
SuiteRunner suiteRunner = (SuiteRunner) suiteRunnerMap.get(xmlSuite);
suiteRunner.run();
//TODO: this should be handled properly
// for (IReporter r : suiteRunner.getReporters()) {
// addListener(r);
// }
// PoolService.getInstance().shutdown();
// Display the final statistics
//
if (xmlSuite.getVerbose() > 0) {
SuiteResultCounts counts = new SuiteResultCounts();
synchronized (suiteRunnerMap) {
counts.calculateResultCounts(xmlSuite, suiteRunnerMap);
}
StringBuffer bufLog = new StringBuffer("\n===============================================\n")
.append(xmlSuite.getName());
bufLog.append("\nTotal tests run: ")
.append(counts.m_total).append(", Failures: ").append(counts.m_failed)
.append(", Skips: ").append(counts.m_skipped);
if(counts.m_confFailures > 0 || counts.m_confSkips > 0) {
bufLog.append("\nConfiguration Failures: ").append(counts.m_confFailures)
.append(", Skips: ").append(counts.m_confSkips);
}
bufLog.append("\n===============================================\n");
System.out.println(bufLog.toString());
}
}
@Override
public void run() {
runSuite(m_suiteRunnerMap, m_suiteRunner.getXmlSuite());
}
@Override
public int compareTo(IWorker<ISuite> arg0) {
/*
* Dummy Implementation
*
* Used by IWorkers to prioritize execution in parallel. Not required by
* this Worker in current implementation
*/
return 0;
}
@Override
public List<ISuite> getTasks() {
List<ISuite> suiteRunnerList = Lists.newArrayList();
suiteRunnerList.add(m_suiteRunner);
return suiteRunnerList;
}
@Override
public String toString() {
return Objects.toStringHelper(getClass())
.add("name", m_suiteRunner.getName())
.toString();
}
@Override
public long getTimeOut()
{
return m_suiteRunner.getXmlSuite().getTimeOut(Long.MAX_VALUE);
}
@Override
public int getPriority()
{
// this class doesnt support priorities yet
return 0;
}
}
/**
* Class to help calculate result counts for tests run as part of a suite and
* its children suites
*
* @author nullin
*
*/
class SuiteResultCounts {
int m_total = 0;
int m_skipped = 0;
int m_failed = 0;
int m_confFailures = 0;
int m_confSkips = 0;
public void calculateResultCounts(XmlSuite xmlSuite, SuiteRunnerMap suiteRunnerMap)
{
ISuite iSuite = suiteRunnerMap.get(xmlSuite);
if (iSuite != null) {
Map<String, ISuiteResult> results = iSuite.getResults();
if (results != null) {
Collection<ISuiteResult> tempSuiteResult = results.values();
for (ISuiteResult isr : tempSuiteResult) {
ITestContext ctx = isr.getTestContext();
int skipped = ctx.getSkippedTests().size();
int failed = ctx.getFailedTests().size() + ctx.getFailedButWithinSuccessPercentageTests().size();
m_skipped += skipped;
m_failed += failed;
m_confFailures += ctx.getFailedConfigurations().size();
m_confSkips += ctx.getSkippedConfigurations().size();
m_total += ctx.getPassedTests().size() + failed + skipped;
}
for (XmlSuite childSuite : xmlSuite.getChildSuites()) {
calculateResultCounts(childSuite, suiteRunnerMap);
}
}
}
}
}
SuiteRunner类:
@Override
public void run() {
invokeListeners(true /* start */);
try {
privateRun();
}
finally {
invokeListeners(false /* stop */);
}
}
private void privateRun() {
// Map for unicity, Linked for guaranteed order
Map<Method, ITestNGMethod> beforeSuiteMethods= new LinkedHashMap<Method, ITestNGMethod>();
Map<Method, ITestNGMethod> afterSuiteMethods = new LinkedHashMap<Method, ITestNGMethod>();
IInvoker invoker = null;
// Get the invoker and find all the suite level methods
for (TestRunner tr: m_testRunners) {
// TODO: Code smell. Invoker should belong to SuiteRunner, not TestRunner
// -- cbeust
invoker = tr.getInvoker();
for (ITestNGMethod m : tr.getBeforeSuiteMethods()) {
beforeSuiteMethods.put(m.getMethod(), m);
}
for (ITestNGMethod m : tr.getAfterSuiteMethods()) {
afterSuiteMethods.put(m.getMethod(), m);
}
}
//
// Invoke beforeSuite methods (the invoker can be null
// if the suite we are currently running only contains
// a <file-suite> tag and no real tests)
//
if (invoker != null) {
if(beforeSuiteMethods.values().size() > 0) {
invoker.invokeConfigurations(null,
beforeSuiteMethods.values().toArray(new ITestNGMethod[beforeSuiteMethods.size()]),
m_suite, m_suite.getParameters(), null, /* no parameter values */
null /* instance */
);
}
Utils.log("SuiteRunner", 3, "Created " + m_testRunners.size() + " TestRunners");
//
// Run all the test runners
//
boolean testsInParallel = XmlSuite.PARALLEL_TESTS.equals(m_suite.getParallel());
if (!testsInParallel) {
runSequentially();
}
else {
runInParallelTestMode();
}
// SuitePlan sp = new SuitePlan();
// for (TestRunner tr : m_testRunners) {
// sp.addTestPlan(tr.getTestPlan());
// }
// sp.dump();
//
// Invoke afterSuite methods
//
if (afterSuiteMethods.values().size() > 0) {
invoker.invokeConfigurations(null,
afterSuiteMethods.values().toArray(new ITestNGMethod[afterSuiteMethods.size()]),
m_suite, m_suite.getAllParameters(), null, /* no parameter values */
null /* instance */);
}
}
}
@Override
public void addListener(ITestNGListener listener) {
if (listener instanceof IInvokedMethodListener) {
m_invokedMethodListeners.add((IInvokedMethodListener) listener);
}
if (listener instanceof ISuiteListener) {
addListener((ISuiteListener) listener);
}
if (listener instanceof IReporter) {
addReporter((IReporter) listener);
}
if (listener instanceof IConfigurationListener) {
addConfigurationListener((IConfigurationListener) listener);
}
}
@Override
public TestRunner newTestRunner(ISuite suite, XmlTest test,
List<IInvokedMethodListener> listeners) {
boolean skip = m_skipFailedInvocationCounts;
if (! skip) {
skip = test.skipFailedInvocationCounts();
}
TestRunner testRunner = new TestRunner(m_configuration, suite, test,
suite.getOutputDirectory(), suite.getAnnotationFinder(), skip,
listeners);
if (m_useDefaultListeners) {
testRunner.addListener(new TestHTMLReporter());
testRunner.addListener(new JUnitXMLReporter());
//TODO: Moved these here because maven2 has output reporters running
//already, the output from these causes directories to be created with
//files. This is not the desired behaviour of running tests in maven2.
//Don't know what to do about this though, are people relying on these
//to be added even with defaultListeners set to false?
testRunner.addListener(new TextReporter(testRunner.getName(), TestRunner.getVerbose()));
}
for (ITestListener itl : m_failureGenerators) {
testRunner.addListener(itl);
}
for (IConfigurationListener cl : m_configuration.getConfigurationListeners()) {
testRunner.addConfigurationListener(cl);
}
return testRunner;
}
}
private static class ProxyTestRunnerFactory implements ITestRunnerFactory {
private ITestListener[] m_failureGenerators;
private ITestRunnerFactory m_target;
public ProxyTestRunnerFactory(ITestListener[] failureListeners, ITestRunnerFactory target) {
m_failureGenerators = failureListeners;
m_target= target;
}
@Override
public TestRunner newTestRunner(ISuite suite, XmlTest test,
List<IInvokedMethodListener> listeners) {
TestRunner testRunner= m_target.newTestRunner(suite, test, listeners);
testRunner.addListener(new TextReporter(testRunner.getName(), TestRunner.getVerbose()));
for (ITestListener itl : m_failureGenerators) {
testRunner.addListener(itl);
}
return testRunner;
}
}
@Override
public Map<String, Collection<ITestNGMethod>> getMethodsByGroups() {
Map<String, Collection<ITestNGMethod>> result = Maps.newHashMap();
for (TestRunner tr : m_testRunners) {
ITestNGMethod[] methods = tr.getAllTestMethods();
for (ITestNGMethod m : methods) {
String[] groups = m.getGroups();
for (String groupName : groups) {
Collection<ITestNGMethod> testMethods = result.get(groupName);
if (null == testMethods) {
testMethods = Lists.newArrayList();
result.put(groupName, testMethods);
}
testMethods.add(m);
}
}
}
return result;
}
/**
* @see org.testng.ISuite#getInvokedMethods()
*/
@Override
public Collection<ITestNGMethod> getInvokedMethods() {
return getIncludedOrExcludedMethods(true /* included */);
}
/**
* @see org.testng.ISuite#getExcludedMethods()
*/
@Override
public Collection<ITestNGMethod> getExcludedMethods() {
return getIncludedOrExcludedMethods(false/* included */);
}
private Collection<ITestNGMethod> getIncludedOrExcludedMethods(boolean included) {
List<ITestNGMethod> result= Lists.newArrayList();
for (TestRunner tr : m_testRunners) {
Collection<ITestNGMethod> methods = included ? tr.getInvokedMethods() : tr.getExcludedMethods();
for (ITestNGMethod m : methods) {
result.add(m);
}
}
return result;
}