Testng 測試框架原始碼閱讀(一)
首先看下 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
接著調入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;
}
相關推薦
Testng 測試框架原始碼閱讀(一)
首先看下 maven-surefire 通過testng拉起單測,執行異常的日誌(有助於我們理解testng中呼叫關係): java.lang.instrument.IllegalClassFormatException: Error while instrumentin
bottle(python的一個小的伺服器框架)的原始碼閱讀(一)
bottle學習的不是很多,用bottle實現了一個連結mongodb的server。 索性bottle的原始碼也不是很多(4000行,主要的程式碼部分)。 所以我就去讀了一下原始碼: from bottle import Bottle, run fr
Spark原始碼閱讀(一)
強烈推薦 https://blog.csdn.net/weixin_41705780/article/details/79273666 總體架構 Spark工程下的模組 spark core, spark 核心 spark streaming, spark流計算(基
Koa原始碼閱讀(一)從搭建Web伺服器說起
先複習一下使用原生 Node.js 搭建一個 Web 伺服器。 var http = require('http'); var server = http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'te
laravel框架原始碼分析(一)自動載入
一、前言 使用php已有好幾年,laravel的使用也是有好長時間,但是一直對於框架原始碼的理解不深,原因很多,歸根到底還是php基礎不紮實,所以原始碼看起來也比較吃力。最近有時間,所以開啟第5、6遍的框架原始碼探索之旅,前面幾次都是看了一些就放棄,希望這次能夠看完。每一次看原始碼都會有新的收穫,因為框
ConcurrentHashMap原始碼閱讀(一)
原始碼所屬版本為jdk1.8 ConcurrentHashMap: public V put(K key, V value) { return putVal(key, value, false); } 這是put方法可以看到呼叫的是put
新手解讀:laravel 框架原始碼分析(一)
眾所周知,php的框架數不勝數,近幾年,一個以優雅著稱的框架,漸漸被國內phper所知道,並且開始使用,但是larave有一個很明顯的缺點就是,他的文件內容少的可憐。而且國內的社群也不是很活躍。所以對使用這款框架的新書造成了很大困難。 作者作為一個入門也沒多久的新手,
Selenium測試結果視覺化工具--Sahagin測試框架使用入門(一)
@Test public void inquiryTest_2() { wd.get("http://www-demo.trident-qa.com/en/contact/"); wd.findElement(By.name("your-name")).clear(); wd.find
AFNetWorking3.2.0原始碼閱讀(一)-AFURLSessionManager.h
AFNetWorking3.2.0原始碼閱讀(一)-AFURLSessionManager.h AFNetWorking3.2.0原始碼閱讀(一)-AFURLSessionManager.h AFURLSessionManager.h 介紹
Executor執行框架原始碼分析(一)——executor、threadFactory、ThreadPoolExecutor 、Future元件的關係及作用
executor執行框架是JDK1.5新增的,用於專注於任務執行的框架。其最大的特點就是將任務的建立和任務的執行分離,鬆耦合,已達到最大限度的利用計算機資源(執行緒和記憶體等)。在併發程式設計中,executor是一個必備的工具。 在分析原始碼之前,首先
Horizon 原始碼閱讀(一)—— Horizon 整體介紹
一、寫在前面 這篇文章主要介紹一下Openstack Horizon — juno專案的整體情況,關於這方面的內容網上已經有很多相關的介紹,我在這裡只作為一個知識的搬運工,把一些分散的內
JUNIT4.11原始碼閱讀(一)--org.junit.Assert類
最近開始閱讀JUNIT4.11原始碼,特寫此文記錄,如有不妥之處煩請指正! 1 原始碼匯入:junit4.11.zip 將檔案解壓,然後獲得5個JAR包,解壓junit-4.11-sources.jar 這裡就是我們最好需要的原始碼 將程式碼匯入ecl
ApiTesting全鏈路自動化測試框架 - 初版釋出(一)
簡介 此框架是基於Python+Pytest+Requests+Allure+Yaml+Json實現全鏈路介面自動化測試。 主要流程:解析介面資料包 ->生成介面基礎配置(yml) ->生成測試用例(yaml+json) ->生成測試指令碼(.py) ->執行測試(pyte
Android Hook框架adbi原始碼淺析(一)
adbi(The Android Dynamic Binary Instrumentation Toolkit)是一個Android平臺通用hook框架,基於動態庫注入與inline hook技術實現。該框架由兩個主要模組構成,1.hijack負責將動態庫注入到目標程序;2.libbase提供動態庫本身,它實
物件池commons-pool框架的研究以及原始碼分析(一)
物件池是一個物件集合,用於將建立好的物件存在該集合中,當需要使用池中的物件時,再從池中取出,恰當地使用物件池可以有效減少物件生成和初始化時的消耗,提高系統的執行效率。另外,利用物件池還可以對物件的狀態做一定的維護,確保物件是可用的,提高程式的健壯性。注意:物件池技術
Java框架學習_SpringMVC(一)SpringMVC的配置和測試使用、SpringMVC的核心架構
SpringMVC+Spring+Mybatis+Maven,SpringMVC是Spring家族的前端框架,具體概念請百度,下面建立工程直接擼 1、SpringMVC的配置和簡單測試使用: 匯入jar包:springmvc所用jar包 工程目錄: 編寫Hell
AFNetworking3.1.0原始碼分析(一)整體框架和功能模組
簡介 1:基於系統NSURLSession類族封裝完成HPPT/HPPTS(GET,PUT,PSOT,DELEATE,HEAD)網路請求 2:擴充套件部分UIKit控制元件,比如擴充套件UIIMag
Darknet 原始碼理解(一)----主體框架的理解
簡介:本系列博文介紹對Darknet原始碼的理解,這一部分為程式主體框架的理解。本博文預設讀者基本熟悉Darknet的使用。正文:darknet的主函式在darknet.c中,其中的main()函式根據終端輸入引數轉向不同的功能函式。若argv[1]= “detector”,
Apache Arrow原始碼分析(一)——簡介和框架
背景 列儲存在資料庫領域中早已被提出,列儲存資料結構在分析型事務上表現優異,大資料分析引擎,諸如Spark-SQL,Impala 均採用列儲存作為其中間資料表示形式,那麼Apache Arrow就是這樣一種記憶體列式資料結構。 在眾多分散式系統中,每
libevent原始碼解讀(一)--總體閱讀
我學習新東西的方法是對新東西有個大概的瞭解,然後在逐步深入。我不知道這種方法好不好,如果有什麼好的學習方法,望推薦! 廢話少說,先下載原始碼然後安裝。本人使用的原始碼是穩定版的libevent-2.0.6。至於他的詳細更新,可以到他的程式碼庫去看。https