这里是基于surefire 2.19.1版本分析的。

还是根据surefire 拉起单元测试执行报错的日志展示的执行过程分析

java.lang.instrument.IllegalClassFormatException: Error while instrumenting class com/suning/imp/scheduler/ActivityDoneMonitorSchedule.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:428)at java.lang.ClassLoader.defineClass1(Native Method)at java.lang.ClassLoader.defineClass(ClassLoader.java:760)at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)at java.net.URLClassLoader.access$100(URLClassLoader.java:73)at java.net.URLClassLoader$1.run(URLClassLoader.java:368)at java.net.URLClassLoader$1.run(URLClassLoader.java:362)at java.security.AccessController.doPrivileged(Native Method)at java.net.URLClassLoader.findClass(URLClassLoader.java:361)at java.lang.ClassLoader.loadClass(ClassLoader.java:424)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)at java.lang.ClassLoader.loadClass(ClassLoader.java:357)at org.springframework.util.ClassUtils.forName(ClassUtils.java:258)at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:417)at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1283)at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1254)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:576)at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1331)at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:341)at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:312)at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:420)at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:617)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451)at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:106)at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:57)at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:313)at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.springTestContextPrepareTestInstance(AbstractTestNGSpringContextTests.java:130)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:497)at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:564)at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:213)at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:175)at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:107)at org.testng.TestRunner.privateRun(TestRunner.java:767)at org.testng.TestRunner.run(TestRunner.java:617)at org.testng.SuiteRunner.runTest(SuiteRunner.java:348)at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:343)at org.testng.SuiteRunner.privateRun(SuiteRunner.java:305)at org.testng.SuiteRunner.run(SuiteRunner.java:254)at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)at org.testng.TestNG.run(TestNG.java:1057)at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:281)at org.apache.maven.surefire.testng.TestNGXmlTestSuite.execute(TestNGXmlTestSuite.java:75)at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:121)at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:290)at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:242)at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:121)
Caused by: java.io.IOException: Error while instrumenting class com/suning/imp/scheduler/ActivityDoneMonitorSchedule.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)... 62 more
Caused by: java.lang.IllegalStateException: Class com/suning/imp/scheduler/ActivityDoneMonitorSchedule 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)... 63 more

-> SuiteRunnerWorker.run -> runSuites

-> SuiteRunner.run -> privateRun -> invokeTestMethods

->testng.internal.TestMethodWorker.run -> invokeTestMethods

->testng.internal.Invoker.invokeTestMethods -> invokeMethod

->testng.internal.MethodInvocationHelper.invokeMethod

然后surefire 通过调用 booter.SurefireBooter.main

(surefire-booter.2.19.1.jar) -> booter.ForkedBooter.runSuitesInProcess

-> booter.ForkedBooter.invokeProviderInSameClassLoader

-> surefire.testng.TestNGProvider.invoke (surefire-testng-2.19.1)
-> surefire.testng.TestNGXmlTestSuite.execute
-> surefire.testng.TestNGExecutor.run

-> TestNG.run(testng-6.9.12)

surefireBooter类代码:

public final class ForkedBooter
{private static final long SYSTEM_EXIT_TIMEOUT_IN_SECONDS = 30;private static final long PING_TIMEOUT_IN_SECONDS = 20;private static final ScheduledExecutorService JVM_TERMINATOR = createJvmTerminator();/*** This method is invoked when Surefire is forked - this method parses and organizes the arguments passed to it and* then calls the Surefire class' run method. <p/> The system exit code will be 1 if an exception is thrown.** @param args Commandline arguments*/public static void main( String... args ){final CommandReader reader = startupMasterProcessReader();final ScheduledFuture<?> pingScheduler = listenToShutdownCommands( reader );final PrintStream originalOut = System.out;try{if ( args.length > 1 ){SystemPropertyManager.setSystemProperties( new File( args[1] ) );}File surefirePropertiesFile = new File( args[0] );InputStream stream = surefirePropertiesFile.exists() ? new FileInputStream( surefirePropertiesFile ) : null;BooterDeserializer booterDeserializer = new BooterDeserializer( stream );ProviderConfiguration providerConfiguration = booterDeserializer.deserialize();final StartupConfiguration startupConfiguration = booterDeserializer.getProviderConfiguration();TypeEncodedValue forkedTestSet = providerConfiguration.getTestForFork();boolean readTestsFromInputStream = providerConfiguration.isReadTestsFromInStream();final ClasspathConfiguration classpathConfiguration = startupConfiguration.getClasspathConfiguration();if ( startupConfiguration.isManifestOnlyJarRequestedAndUsable() ){classpathConfiguration.trickClassPathWhenManifestOnlyClasspath();}ClassLoader classLoader = Thread.currentThread().getContextClassLoader();classLoader.setDefaultAssertionStatus( classpathConfiguration.isEnableAssertions() );startupConfiguration.writeSurefireTestClasspathProperty();final Object testSet;if ( forkedTestSet != null ){testSet = forkedTestSet.getDecodedValue( classLoader );}else if ( readTestsFromInputStream ){testSet = new LazyTestsToRun( originalOut );}else{testSet = null;}try{runSuitesInProcess( testSet, startupConfiguration, providerConfiguration, originalOut );}catch ( InvocationTargetException t ){LegacyPojoStackTraceWriter stackTraceWriter =new LegacyPojoStackTraceWriter( "test subystem", "no method", t.getTargetException() );StringBuilder stringBuilder = new StringBuilder();encode( stringBuilder, stackTraceWriter, false );encodeAndWriteToOutput( ( (char) BOOTERCODE_ERROR ) + ",0," + stringBuilder + "\n" , originalOut );}catch ( Throwable t ){StackTraceWriter stackTraceWriter = new LegacyPojoStackTraceWriter( "test subystem", "no method", t );StringBuilder stringBuilder = new StringBuilder();encode( stringBuilder, stackTraceWriter, false );encodeAndWriteToOutput( ( (char) BOOTERCODE_ERROR ) + ",0," + stringBuilder + "\n", originalOut );}// Say bye.encodeAndWriteToOutput( ( (char) BOOTERCODE_BYE ) + ",0,BYE!\n", originalOut );originalOut.flush();// noinspection CallToSystemExitexit( 0, EXIT, reader, false );}catch ( Throwable t ){// Just throwing does getMessage() and a local trace - we want to call printStackTrace for a full trace// noinspection UseOfSystemOutOrSystemErrt.printStackTrace( System.err );// noinspection ProhibitedExceptionThrown,CallToSystemExitexit( 1, EXIT, reader, false );}finally{pingScheduler.cancel( true );}}private static CommandReader startupMasterProcessReader(){return CommandReader.getReader();}private static ScheduledFuture<?> listenToShutdownCommands( CommandReader reader ){reader.addShutdownListener( createExitHandler( reader ) );AtomicBoolean pingDone = new AtomicBoolean( true );reader.addNoopListener( createPingHandler( pingDone ) );return JVM_TERMINATOR.scheduleAtFixedRate( createPingJob( pingDone, reader ),0, PING_TIMEOUT_IN_SECONDS, SECONDS );}private static CommandListener createPingHandler( final AtomicBoolean pingDone ){return new CommandListener(){public void update( Command command ){pingDone.set( true );}};}private static CommandListener createExitHandler( final CommandReader reader ){return new CommandListener(){public void update( Command command ){exit( 1, command.toShutdownData(), reader, true );}};}private static Runnable createPingJob( final AtomicBoolean pingDone, final CommandReader reader  ){return new Runnable(){public void run(){boolean hasPing = pingDone.getAndSet( false );if ( !hasPing ){exit( 1, KILL, reader, true );}}};}private static void encodeAndWriteToOutput( String string, PrintStream out ){byte[] encodeBytes = encodeStringForForkCommunication( string );out.write( encodeBytes, 0, encodeBytes.length );}private static void exit( int returnCode, Shutdown shutdownType, CommandReader reader, boolean stopReaderOnExit ){switch ( shutdownType ){case KILL:Runtime.getRuntime().halt( returnCode );case EXIT:if ( stopReaderOnExit ){reader.stop();}launchLastDitchDaemonShutdownThread( returnCode );System.exit( returnCode );case DEFAULT:// refers to shutdown=testset, but not used now, keeping reader opendefault:break;}}private static RunResult runSuitesInProcess( Object testSet, StartupConfiguration startupConfiguration,ProviderConfiguration providerConfiguration,PrintStream originalSystemOut )throws SurefireExecutionException, TestSetFailedException, InvocationTargetException{final ReporterFactory factory = createForkingReporterFactory( providerConfiguration, originalSystemOut );return invokeProviderInSameClassLoader( testSet, factory, providerConfiguration, true, startupConfiguration,false );}private static ReporterFactory createForkingReporterFactory( ProviderConfiguration providerConfiguration,PrintStream originalSystemOut ){final boolean trimStackTrace = providerConfiguration.getReporterConfiguration().isTrimStackTrace();return SurefireReflector.createForkingReporterFactoryInCurrentClassLoader( trimStackTrace, originalSystemOut );}private static ScheduledExecutorService createJvmTerminator(){ThreadFactory threadFactory = newDaemonThreadFactory( "last-ditch-daemon-shutdown-thread-"+ SYSTEM_EXIT_TIMEOUT_IN_SECONDS+ "sec" );ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor( 1, threadFactory );executor.setMaximumPoolSize( 1 );executor.prestartCoreThread();return executor;}@SuppressWarnings( "checkstyle:emptyblock" )private static void launchLastDitchDaemonShutdownThread( final int returnCode ){JVM_TERMINATOR.schedule( new Runnable(){public void run(){Runtime.getRuntime().halt( returnCode );}}, SYSTEM_EXIT_TIMEOUT_IN_SECONDS, SECONDS );}private static RunResult invokeProviderInSameClassLoader( Object testSet, Object factory,ProviderConfiguration providerConfiguration,boolean insideFork,StartupConfiguration startupConfig,boolean restoreStreams )throws TestSetFailedException, InvocationTargetException{final PrintStream orgSystemOut = System.out;final PrintStream orgSystemErr = System.err;// Note that System.out/System.err are also read in the "ReporterConfiguration" instatiation// in createProvider below. These are the same values as here.try{return createProviderInCurrentClassloader( startupConfig, insideFork, providerConfiguration, factory ).invoke( testSet );}finally{if ( restoreStreams && System.getSecurityManager() == null ){System.setOut( orgSystemOut );System.setErr( orgSystemErr );}}}private static SurefireProvider createProviderInCurrentClassloader( StartupConfiguration startupConfiguration1,boolean isInsideFork,ProviderConfiguration providerConfiguration,Object reporterManagerFactory1 ){BaseProviderFactory bpf = new BaseProviderFactory( (ReporterFactory) reporterManagerFactory1, isInsideFork );bpf.setTestRequest( providerConfiguration.getTestSuiteDefinition() );bpf.setReporterConfiguration( providerConfiguration.getReporterConfiguration() );ClassLoader classLoader = Thread.currentThread().getContextClassLoader();bpf.setClassLoaders( classLoader );bpf.setTestArtifactInfo( providerConfiguration.getTestArtifact() );bpf.setProviderProperties( providerConfiguration.getProviderProperties() );bpf.setRunOrderParameters( providerConfiguration.getRunOrderParameters() );bpf.setDirectoryScannerParameters( providerConfiguration.getDirScannerParams() );bpf.setMainCliOptions( providerConfiguration.getMainCliOptions() );bpf.setSkipAfterFailureCount( providerConfiguration.getSkipAfterFailureCount() );bpf.setShutdown( providerConfiguration.getShutdown() );String providerClass = startupConfiguration1.getActualClassName();return (SurefireProvider) ReflectionUtils.instantiateOneArg( classLoader, providerClass, ProviderParameters.class, bpf );}
}

最关键的方法是上述代码中:

 private static SurefireProvider createProviderInCurrentClassloader(StartupConfiguration startupConfiguration1, boolean isInsideFork, ProviderConfiguration providerConfiguration, Object reporterManagerFactory1){BaseProviderFactory bpf = new BaseProviderFactory((ReporterFactory)reporterManagerFactory1, isInsideFork);bpf.setTestRequest(providerConfiguration.getTestSuiteDefinition());bpf.setReporterConfiguration(providerConfiguration.getReporterConfiguration());ClassLoader classLoader = Thread.currentThread().getContextClassLoader();bpf.setClassLoaders(classLoader);bpf.setTestArtifactInfo(providerConfiguration.getTestArtifact());bpf.setProviderProperties(providerConfiguration.getProviderProperties());bpf.setRunOrderParameters(providerConfiguration.getRunOrderParameters());bpf.setDirectoryScannerParameters(providerConfiguration.getDirScannerParams());bpf.setMainCliOptions(providerConfiguration.getMainCliOptions());bpf.setSkipAfterFailureCount(providerConfiguration.getSkipAfterFailureCount());bpf.setShutdown(providerConfiguration.getShutdown());String providerClass = startupConfiguration1.getActualClassName();return (SurefireProvider)ReflectionUtils.instantiateOneArg(classLoader, providerClass, ProviderParameters.class, bpf);}

ReflectionUtils 来自 surefire-api.jar(2.19.1)  代码:

public static Object instantiateOneArg(ClassLoader classLoader, String className, Class<?> param1Class, Object param1){try{Class<?> aClass = loadClass(classLoader, className);Constructor constructor = getConstructor(aClass, new Class[] { param1Class });return constructor.newInstance(new Object[] { param1 });}catch (InvocationTargetException e){throw new SurefireReflectionException(e.getTargetException());}catch (InstantiationException e){throw new SurefireReflectionException(e);}catch (IllegalAccessException e){throw new SurefireReflectionException(e);}}public static Object instantiateTwoArgs(ClassLoader classLoader, String className, Class<?> param1Class, Object param1, Class param2Class, Object param2){try{Class<?> aClass = loadClass(classLoader, className);Constructor constructor = getConstructor(aClass, new Class[] { param1Class, param2Class });return constructor.newInstance(new Object[] { param1, param2 });}catch (InvocationTargetException e){throw new SurefireReflectionException(e.getTargetException());}catch (InstantiationException e){throw new SurefireReflectionException(e);}catch (IllegalAccessException e){throw new SurefireReflectionException(e);}}public static void invokeSetter(Object o, String name, Class<?> value1clazz, Object value){Method setter = getMethod(o, name, new Class[] { value1clazz });invokeSetter(o, setter, value);}public static Object invokeSetter(Object target, Method method, Object value){return invokeMethodWithArray(target, method, new Object[] { value });}public static Object invokeMethodWithArray(Object target, Method method, Object... args){try{return method.invoke(target, args);}catch (IllegalAccessException e){throw new SurefireReflectionException(e);}catch (InvocationTargetException e){throw new SurefireReflectionException(e.getTargetException());}}public static Object invokeMethodWithArray2(Object target, Method method, Object... args)throws InvocationTargetException{try{return method.invoke(target, args);}catch (IllegalAccessException e){throw new SurefireReflectionException(e);}}public static Object instantiateObject(String className, Class[] types, Object[] params, ClassLoader classLoader){Class<?> clazz = loadClass(classLoader, className);Constructor constructor = getConstructor(clazz, types);return newInstance(constructor, params);}public static Class<?> tryLoadClass(ClassLoader classLoader, String className){try{return classLoader.loadClass(className);}catch (NoClassDefFoundError localNoClassDefFoundError) {}catch (ClassNotFoundException localClassNotFoundException) {}return null;}public static Class<?> loadClass(ClassLoader classLoader, String className){try{return classLoader.loadClass(className);}catch (NoClassDefFoundError e){throw new SurefireReflectionException(e);}catch (ClassNotFoundException e){throw new SurefireReflectionException(e);}}
public static Object newInstance(Constructor constructor, Object... params){try{return constructor.newInstance(params);}catch (InvocationTargetException e){throw new SurefireReflectionException(e);}catch (InstantiationException e){throw new SurefireReflectionException(e);}catch (IllegalAccessException e){throw new SurefireReflectionException(e);}}public static <T> T instantiate(ClassLoader classLoader, String classname, Class<T> returnType){try{Class<?> clazz = loadClass(classLoader, classname);return returnType.cast(clazz.newInstance());}catch (InstantiationException e){throw new SurefireReflectionException(e);}catch (IllegalAccessException e){throw new SurefireReflectionException(e);}}public static Object instantiateOneArg(ClassLoader classLoader, String className, Class<?> param1Class, Object param1){try{Class<?> aClass = loadClass(classLoader, className);Constructor constructor = getConstructor(aClass, new Class[] { param1Class });return constructor.newInstance(new Object[] { param1 });}catch (InvocationTargetException e){throw new SurefireReflectionException(e.getTargetException());}catch (InstantiationException e){throw new SurefireReflectionException(e);}catch (IllegalAccessException e){throw new SurefireReflectionException(e);}}

传入的是SurefireProvider 类型,其实它是接口,代码如下:

public abstract interface SurefireProvider
{public abstract Iterable<Class<?>> getSuites();public abstract RunResult invoke(Object paramObject)throws TestSetFailedException, ReporterException, InvocationTargetException;public abstract void cancel();
}

还有一个很关键的接口扩展 了 SurefireProvider ,它就是AbstractProvider 接口:

public abstract class AbstractProviderimplements SurefireProvider
{private final Thread creatingThread = Thread.currentThread();public void cancel(){synchronized (this.creatingThread){if (this.creatingThread.isAlive()) {this.creatingThread.interrupt();}}}
}

然后 surefire-testng.jar 中TestNGProvider代码:

public class TestNGProviderextends AbstractProvider
{private final Map<String, String> providerProperties;private final ReporterConfiguration reporterConfiguration;private final ClassLoader testClassLoader;private final ScanResult scanResult;private final TestRequest testRequest;private final ProviderParameters providerParameters;private final RunOrderCalculator runOrderCalculator;private final List<CommandLineOption> mainCliOptions;private final CommandReader commandsReader;private TestsToRun testsToRun;public TestNGProvider( ProviderParameters bootParams ){// don't start a thread in CommandReader while we are in in-plugin processcommandsReader = bootParams.isInsideFork() ? getReader().setShutdown( bootParams.getShutdown() ) : null;providerParameters = bootParams;testClassLoader = bootParams.getTestClassLoader();runOrderCalculator = bootParams.getRunOrderCalculator();providerProperties = bootParams.getProviderProperties();testRequest = bootParams.getTestRequest();reporterConfiguration = bootParams.getReporterConfiguration();scanResult = bootParams.getScanResult();mainCliOptions = bootParams.getMainCliOptions();}public RunResult invoke( Object forkTestSet )throws TestSetFailedException{if ( isFailFast() && commandsReader != null ){registerPleaseStopListener();}final ReporterFactory reporterFactory = providerParameters.getReporterFactory();final RunListener reporter = reporterFactory.createReporter();/*** {@link org.apache.maven.surefire.report.ConsoleOutputCapture#startCapture(ConsoleOutputReceiver)}* called in prior to initializing variable {@link #testsToRun}*/startCapture( (ConsoleOutputReceiver) reporter );RunResult runResult;try{if ( isTestNGXmlTestSuite( testRequest ) ){if ( commandsReader != null ){commandsReader.awaitStarted();}TestNGXmlTestSuite testNGXmlTestSuite = newXmlSuite();testNGXmlTestSuite.locateTestSets();testNGXmlTestSuite.execute( reporter );}else{if ( testsToRun == null ){if ( forkTestSet instanceof TestsToRun ){testsToRun = (TestsToRun) forkTestSet;}else if ( forkTestSet instanceof Class ){testsToRun = fromClass( (Class<?>) forkTestSet );}else{testsToRun = scanClassPath();}}if ( commandsReader != null ){registerShutdownListener( testsToRun );commandsReader.awaitStarted();}TestNGDirectoryTestSuite suite = newDirectorySuite();suite.execute( testsToRun, reporter );}}finally{runResult = reporterFactory.close();}return runResult;}boolean isTestNGXmlTestSuite( TestRequest testSuiteDefinition ){Collection<File> suiteXmlFiles = testSuiteDefinition.getSuiteXmlFiles();return !suiteXmlFiles.isEmpty() && !hasSpecificTests();}private boolean isFailFast(){return providerParameters.getSkipAfterFailureCount() > 0;}private int getSkipAfterFailureCount(){return isFailFast() ? providerParameters.getSkipAfterFailureCount() : 0;}private void registerShutdownListener( final TestsToRun testsToRun ){commandsReader.addShutdownListener( new CommandListener(){public void update( Command command ){testsToRun.markTestSetFinished();}} );}private void registerPleaseStopListener(){commandsReader.addSkipNextTestsListener( new CommandListener(){public void update( Command command ){FailFastEventsSingleton.getInstance().setSkipOnNextTest();}} );}private TestNGDirectoryTestSuite newDirectorySuite(){return new TestNGDirectoryTestSuite( testRequest.getTestSourceDirectory().toString(), providerProperties,reporterConfiguration.getReportsDirectory(), getTestFilter(),mainCliOptions, getSkipAfterFailureCount() );}private TestNGXmlTestSuite newXmlSuite(){return new TestNGXmlTestSuite( testRequest.getSuiteXmlFiles(),testRequest.getTestSourceDirectory().toString(),providerProperties,reporterConfiguration.getReportsDirectory(), getSkipAfterFailureCount() );}public Iterable<Class<?>> getSuites(){if ( isTestNGXmlTestSuite( testRequest ) ){return Collections.emptySet();}else{testsToRun = scanClassPath();return testsToRun;}}private TestsToRun scanClassPath(){final TestsToRun scanned = scanResult.applyFilter( null, testClassLoader );return runOrderCalculator.orderTestClasses( scanned );}private boolean hasSpecificTests(){TestListResolver specificTestPatterns = testRequest.getTestListResolver();return !specificTestPatterns.isEmpty() && !specificTestPatterns.isWildcard();}private TestListResolver getTestFilter(){TestListResolver filter = optionallyWildcardFilter( testRequest.getTestListResolver() );return filter.isWildcard() ? getEmptyTestListResolver() : filter;}
}

ProviderParameters接口代码:

public abstract interface ProviderParameters
{/*** @deprecated*/public abstract DirectoryScanner getDirectoryScanner();public abstract ScanResult getScanResult();public abstract RunOrderCalculator getRunOrderCalculator();public abstract ReporterFactory getReporterFactory();public abstract ConsoleLogger getConsoleLogger();@Deprecatedpublic abstract DirectoryScannerParameters getDirectoryScannerParameters();public abstract ReporterConfiguration getReporterConfiguration();public abstract TestRequest getTestRequest();public abstract ClassLoader getTestClassLoader();public abstract Map<String, String> getProviderProperties();public abstract TestArtifactInfo getTestArtifactInfo();public abstract List<CommandLineOption> getMainCliOptions();public abstract int getSkipAfterFailureCount();public abstract boolean isInsideFork();public abstract Shutdown getShutdown();

ScanResult接口代码:

public abstract interface ScanResult
{public abstract int size();public abstract String getClassName(int paramInt);public abstract TestsToRun applyFilter(ScannerFilter paramScannerFilter, ClassLoader paramClassLoader);public abstract List<Class<?>> getClassesSkippedByValidation(ScannerFilter paramScannerFilter, ClassLoader paramClassLoader);public abstract void writeTo(Map<String, String> paramMap);
}

TestsToRun代码:

public class TestsToRunimplements Iterable<Class<?>>
{private final List<Class<?>> locatedClasses;private volatile boolean finished;private int iteratedCount;public TestsToRun(Set<Class<?>> locatedClasses){this.locatedClasses = new ArrayList(locatedClasses);}public static TestsToRun fromClass(Class<?> clazz)throws TestSetFailedException{return new TestsToRun(Collections.singleton(clazz));}public Iterator<Class<?>> iterated(){return newWeakIterator();}public Iterator<Class<?>> iterator(){return new ClassesIterator(null);}private final class ClassesIteratorextends CloseableIterator<Class<?>>{private final Iterator<Class<?>> it = TestsToRun.this.locatedClasses.iterator();private int iteratedCount;private ClassesIterator() {}protected boolean isClosed(){return TestsToRun.this.isFinished();}protected boolean doHasNext(){return this.it.hasNext();}protected Class<?> doNext(){Class<?> nextTest = (Class)this.it.next();TestsToRun.this.iteratedCount = Math.max(++this.iteratedCount, TestsToRun.this.iteratedCount);return nextTest;}protected void doRemove() {}public void remove(){throw new UnsupportedOperationException("unsupported remove");}}public final void markTestSetFinished(){this.finished = true;}public final boolean isFinished(){return this.finished;}public String toString(){StringBuilder sb = new StringBuilder("TestsToRun: [");for (Class<?> clazz : this) {sb.append(' ').append(clazz.getName());}sb.append(']');return sb.toString();}public boolean containsAtLeast(int atLeast){return containsAtLeast(iterator(), atLeast);}private boolean containsAtLeast(Iterator<Class<?>> it, int atLeast){for (int i = 0; i < atLeast; i++){if (!it.hasNext()) {return false;}it.next();}return true;}public boolean containsExactly(int items){Iterator<Class<?>> it = iterator();return (containsAtLeast(it, items)) && (!it.hasNext());}public boolean allowEagerReading(){return true;}public Class<?>[] getLocatedClasses(){if (!allowEagerReading()) {throw new IllegalStateException("Cannot eagerly read");}Collection<Class<?>> result = new ArrayList();for (Class<?> clazz : this) {result.add(clazz);}return (Class[])result.toArray(new Class[result.size()]);}public Class<?> getClassByName(String className){for (Class<?> clazz : this) {if (clazz.getName().equals(className)) {return clazz;}}return null;}private Iterator<Class<?>> newWeakIterator(){final Iterator<Class<?>> it = this.locatedClasses.subList(0, this.iteratedCount).iterator();new CloseableIterator(){protected boolean isClosed(){return TestsToRun.this.isFinished();}protected boolean doHasNext(){return it.hasNext();}protected Class<?> doNext(){return (Class)it.next();}protected void doRemove() {}public void remove(){throw new UnsupportedOperationException("unsupported remove");}};}
}

TestNGXmlTestSuite类代码:

import static org.apache.maven.surefire.testng.TestNGExecutor.run;/*** Handles suite xml file definitions for TestNG.** @author jkuhnert* @author <a href='mailto:the[dot]mindstorm[at]gmail[dot]com'>Alex Popescu</a>*/
final class TestNGXmlTestSuiteextends TestSuite
{private final List<File> suiteFiles;private List<String> suiteFilePaths;private final String testSourceDirectory;private final Map<String, String> options;private final File reportsDirectory;private final int skipAfterFailureCount;/*** Creates a testng testset to be configured by the specified* xml file(s). The XML files are suite definitions files according to TestNG DTD.*/TestNGXmlTestSuite( List<File> suiteFiles, String testSourceDirectory, Map<String, String> confOptions,File reportsDirectory, int skipAfterFailureCount ){this.suiteFiles = suiteFiles;this.options = confOptions;this.testSourceDirectory = testSourceDirectory;this.reportsDirectory = reportsDirectory;this.skipAfterFailureCount = skipAfterFailureCount;}void execute( RunListener reporter )throws TestSetFailedException{if ( suiteFilePaths == null ){throw new IllegalStateException( "You must call locateTestSets before calling execute" );}startTestSuite( reporter );run( suiteFilePaths, testSourceDirectory, options, reporter, reportsDirectory, skipAfterFailureCount );finishTestSuite( reporter );}void locateTestSets()throws TestSetFailedException{if ( suiteFilePaths != null ){throw new IllegalStateException( "You can't call locateTestSets twice" );}if ( suiteFiles.isEmpty() ){throw new IllegalStateException( "No suite files were specified" );}suiteFilePaths = new ArrayList<String>();for ( File suiteFile : suiteFiles ){if ( !suiteFile.isFile() ){throw new TestSetFailedException( "Suite file " + suiteFile + " is not a valid file" );}suiteFilePaths.add( suiteFile.getAbsolutePath() );}}@OverrideMap<String, String> getOptions(){return options;}
}

import static org.apache.maven.surefire.testng.TestNGExecutor.run; 直接执行 TestNGExecutor.run

final class TestNGExecutor
{/** The default name for a suite launched from the maven surefire plugin */private static final String DEFAULT_SUREFIRE_SUITE_NAME = "Surefire suite";/** The default name for a test launched from the maven surefire plugin */private static final String DEFAULT_SUREFIRE_TEST_NAME = "Surefire test";private static final boolean HAS_TEST_ANNOTATION_ON_CLASSPATH =tryLoadClass( TestNGExecutor.class.getClassLoader(), "org.testng.annotations.Test" ) != null;private TestNGExecutor(){throw new IllegalStateException( "not instantiable constructor" );}static void run( Iterable<Class<?>> testClasses, String testSourceDirectory,Map<String, String> options, // string,string because TestNGMapConfigurator#configure()RunListener reportManager, File reportsDirectory,TestListResolver methodFilter, List<CommandLineOption> mainCliOptions,int skipAfterFailureCount )throws TestSetFailedException{TestNG testng = new TestNG( true );Configurator configurator = getConfigurator( options.get( "testng.configurator" ) );if ( isCliDebugOrShowErrors( mainCliOptions ) ){System.out.println( "Configuring TestNG with: " + configurator.getClass().getSimpleName() );}XmlMethodSelector groupMatchingSelector = createGroupMatchingSelector( options );XmlMethodSelector methodNameFilteringSelector = createMethodNameFilteringSelector( methodFilter );Map<String, SuiteAndNamedTests> suitesNames = new HashMap<String, SuiteAndNamedTests>();List<XmlSuite> xmlSuites = new ArrayList<XmlSuite>();for ( Class<?> testClass : testClasses ){TestMetadata metadata = findTestMetadata( testClass );SuiteAndNamedTests suiteAndNamedTests = suitesNames.get( metadata.suiteName );if ( suiteAndNamedTests == null ){suiteAndNamedTests = new SuiteAndNamedTests();suiteAndNamedTests.xmlSuite.setName( metadata.suiteName );configurator.configure( suiteAndNamedTests.xmlSuite, options );xmlSuites.add( suiteAndNamedTests.xmlSuite );suitesNames.put( metadata.suiteName, suiteAndNamedTests );}XmlTest xmlTest = suiteAndNamedTests.testNameToTest.get( metadata.testName );if ( xmlTest == null ){xmlTest = new XmlTest( suiteAndNamedTests.xmlSuite );xmlTest.setName( metadata.testName );addSelector( xmlTest, groupMatchingSelector );addSelector( xmlTest, methodNameFilteringSelector );xmlTest.setXmlClasses( new ArrayList<XmlClass>() );suiteAndNamedTests.testNameToTest.put( metadata.testName, xmlTest );}xmlTest.getXmlClasses().add( new XmlClass( testClass.getName() ) );}testng.setXmlSuites( xmlSuites );configurator.configure( testng, options );postConfigure( testng, testSourceDirectory, reportManager, reportsDirectory, skipAfterFailureCount,extractVerboseLevel( options ) );testng.run();}private static boolean isCliDebugOrShowErrors( List<CommandLineOption> mainCliOptions ){return mainCliOptions.contains( CommandLineOption.LOGGING_LEVEL_DEBUG )|| mainCliOptions.contains( CommandLineOption.SHOW_ERRORS );}private static TestMetadata findTestMetadata( Class<?> testClass ){TestMetadata result = new TestMetadata();if ( HAS_TEST_ANNOTATION_ON_CLASSPATH ){Test testAnnotation = findAnnotation( testClass, Test.class );if ( null != testAnnotation ){if ( !StringUtils.isBlank( testAnnotation.suiteName() ) ){result.suiteName = testAnnotation.suiteName();}if ( !StringUtils.isBlank( testAnnotation.testName() ) ){result.testName = testAnnotation.testName();}}}return result;}private static <T extends Annotation> T findAnnotation( Class<?> clazz, Class<T> annotationType ){if ( clazz == null ){return null;}T result = clazz.getAnnotation( annotationType );if ( result != null ){return result;}return findAnnotation( clazz.getSuperclass(), annotationType );}private static class TestMetadata{private String testName = DEFAULT_SUREFIRE_TEST_NAME;private String suiteName = DEFAULT_SUREFIRE_SUITE_NAME;}private static class SuiteAndNamedTests{private XmlSuite xmlSuite = new XmlSuite();private Map<String, XmlTest> testNameToTest = new HashMap<String, XmlTest>();}private static void addSelector( XmlTest xmlTest, XmlMethodSelector selector ){if ( selector != null ){xmlTest.getMethodSelectors().add( selector );}}@SuppressWarnings( "checkstyle:magicnumber" )private static XmlMethodSelector createMethodNameFilteringSelector( TestListResolver methodFilter )throws TestSetFailedException{if ( methodFilter != null && !methodFilter.isEmpty() ){// the class is available in the testClassPathString clazzName = "org.apache.maven.surefire.testng.utils.MethodSelector";try{Class<?> clazz = Class.forName( clazzName );Method method = clazz.getMethod( "setTestListResolver", TestListResolver.class );method.invoke( null, methodFilter );}catch ( Exception e ){throw new TestSetFailedException( e.getMessage(), e );}XmlMethodSelector xms = new XmlMethodSelector();xms.setName( clazzName );// looks to need a high valuexms.setPriority( 10000 );return xms;}else{return null;}}@SuppressWarnings( "checkstyle:magicnumber" )private static XmlMethodSelector createGroupMatchingSelector( Map<String, String> options )throws TestSetFailedException{final String groups = options.get( ProviderParameterNames.TESTNG_GROUPS_PROP );final String excludedGroups = options.get( ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP );if ( groups == null && excludedGroups == null ){return null;}// the class is available in the testClassPathfinal String clazzName = "org.apache.maven.surefire.testng.utils.GroupMatcherMethodSelector";try{Class<?> clazz = Class.forName( clazzName );// HORRIBLE hack, but TNG doesn't allow us to setup a method selector instance directly.Method method = clazz.getMethod( "setGroups", String.class, String.class );method.invoke( null, groups, excludedGroups );}catch ( Exception e ){throw new TestSetFailedException( e.getMessage(), e );}XmlMethodSelector xms = new XmlMethodSelector();xms.setName( clazzName );// looks to need a high valuexms.setPriority( 9999 );return xms;}static void run( List<String> suiteFiles, String testSourceDirectory,Map<String, String> options, // string,string because TestNGMapConfigurator#configure()RunListener reportManager, File reportsDirectory, int skipAfterFailureCount )throws TestSetFailedException{TestNG testng = new TestNG( true );Configurator configurator = getConfigurator( options.get( "testng.configurator" ) );configurator.configure( testng, options );postConfigure( testng, testSourceDirectory, reportManager, reportsDirectory, skipAfterFailureCount,extractVerboseLevel( options ) );testng.setTestSuites( suiteFiles );testng.run();}private static Configurator getConfigurator( String className ){try{return (Configurator) Class.forName( className ).newInstance();}catch ( InstantiationException e ){throw new RuntimeException( e );}catch ( IllegalAccessException e ){throw new RuntimeException( e );}catch ( ClassNotFoundException e ){throw new RuntimeException( e );}}private static void postConfigure( TestNG testNG, String sourcePath, final RunListener reportManager,File reportsDirectory, int skipAfterFailureCount, int verboseLevel ){// 0 (default): turn off all TestNG outputtestNG.setVerbose( verboseLevel );TestNGReporter reporter = createTestNGReporter( reportManager );testNG.addListener( (Object) reporter );if ( skipAfterFailureCount > 0 ){ClassLoader cl = Thread.currentThread().getContextClassLoader();testNG.addListener( instantiate( cl, "org.apache.maven.surefire.testng.utils.FailFastNotifier",Object.class ) );testNG.addListener( new FailFastListener( createStoppable( reportManager, skipAfterFailureCount ) ) );}// FIXME: use classifier to decide if we need to pass along the source dir (only for JDK14)if ( sourcePath != null ){testNG.setSourcePath( sourcePath );}testNG.setOutputDirectory( reportsDirectory.getAbsolutePath() );}private static Stoppable createStoppable( final RunListener reportManager, int skipAfterFailureCount ){final AtomicInteger currentFaultCount = new AtomicInteger( skipAfterFailureCount );return new Stoppable(){public void fireStopEvent(){if ( countDownToZero( currentFaultCount ) ){FailFastEventsSingleton.getInstance().setSkipOnNextTest();}reportManager.testExecutionSkippedByUser();}};}// If we have access to IResultListener, return a ConfigurationAwareTestNGReporter// But don't cause NoClassDefFoundErrors if it isn't available; just return a regular TestNGReporter insteadprivate static TestNGReporter createTestNGReporter( RunListener reportManager ){try{Class.forName( "org.testng.internal.IResultListener" );Class c = Class.forName( "org.apache.maven.surefire.testng.ConfigurationAwareTestNGReporter" );@SuppressWarnings( "unchecked" ) Constructor<?> ctor = c.getConstructor( RunListener.class );return (TestNGReporter) ctor.newInstance( reportManager );}catch ( InvocationTargetException e ){throw new RuntimeException( "Bug in ConfigurationAwareTestNGReporter", e.getCause() );}catch ( ClassNotFoundException e ){return new TestNGReporter( reportManager );}catch ( Exception e ){throw new RuntimeException( "Bug in ConfigurationAwareTestNGReporter", e );}}private static int extractVerboseLevel( Map<String, String> options )throws TestSetFailedException{try{String verbose = options.get( "surefire.testng.verbose" );return verbose == null ? 0 : Integer.parseInt( verbose );}catch ( NumberFormatException e ){throw new TestSetFailedException( "Provider property 'surefire.testng.verbose' should refer to "+ "number -1 (debug mode), 0, 1 .. 10 (most detailed).", e );}}
}

run 方法中直接调用

TestNG testng = new TestNG( true );

surefire 拉起testng单元测试类的源码流程阅读(二)相关推荐

  1. surefire 拉起testng单元测试类的源码流程阅读(一)

    这里分析是基于2.5surefire 版本. 首先拿surefire 拉起单元测试报错日志 分析: Caused by: java.io.IOException: Error while instru ...

  2. surefire 拉起 junit 单元测试类 源码阅读(一)

    根据surefire 拉起Junit单元测试类 输出的报错日志 跟踪执行过程: 日志1: java.lang.reflect.InvocationTargetExceptionat sun.refle ...

  3. surefire 拉起 junit 单元测试类 源码阅读(二)

    根据上一篇blog,看到日志1流程: surefire.ForkedBooter -> ForkedBooter.runSuitesInProcess -> ForkedBooter.in ...

  4. 单元测试源码分析之二Mockito自动装配和插桩

    前面分析过了Mockito是如何通过注解创建对应的mock对象,并对其所有方法设置拦截器.这篇博客再分析下Mockito是如何实现自动装配和插桩的,只有更好的了解其原理,在写复杂单测的时候才能更加得心 ...

  5. 24 UsageEnvironment使用环境抽象基类——Live555源码阅读(三)UsageEnvironment

    24 UsageEnvironment使用环境抽象基类--Live555源码阅读(三)UsageEnvironment 24 UsageEnvironment使用环境抽象基类--Live555源码阅读 ...

  6. 【Linux 内核】实时调度类 ③ ( 实时调度类 rt_sched_class 源码 | 调度类 sched_class 源码 )

    文章目录 一.调度类 ( 停机调度类 | 限期调度类 | 实时调度类 | 公平调度类 | 空闲调度类 ) 二. 实时调度类 rt_sched_class 源码 一.调度类 ( 停机调度类 | 限期调度 ...

  7. PHP密码生成管理源码,php密码生成类(附源码)

    本节内容: 好用的php 密码生成类. 访代码实现的功能: 1,可设定密码长度. 2,可设定要生成的密码个数,批量生成. 3,可以指定密码的规则,字母,数字,特殊字符等. 1,密码生成类文件 Gene ...

  8. 12 哈希表相关类——Live555源码阅读(一)基本组件类

    12 哈希表相关类--Live555源码阅读(一)基本组件类 这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 ...

  9. php强制cookies,php Cookies操作类(附源码)

    本cookies操作类的功能,包括: 1,保存,读取,更新,清除cookies数据. 2,可设置前缀. 3,强制超时控制. 4,cookies数据可以是字符串,数组,对象等. 1,PHP cookie ...

最新文章

  1. cas协议,以及tomcat搭建cas服务器
  2. 软件架构设计之常用架构模式
  3. java乱码怎么解决_如何解决java乱码
  4. 使用Python重命名MP3标签
  5. http 请求头和响应头
  6. SpringBoot使用@Cacheable实现最简单的Redis缓存
  7. linux 报错 bash ‘/bin/sh: Syntax error: “(” unexpected
  8. java十六进制与字符串_JAVA十六进制与字符串的转换方法
  9. flume正则拦截器
  10. 软件需求与分析——大二下需会知识点
  11. Java设计模式-单例模式实际应用场景
  12. vmware 官方下载
  13. Unity学习:瓦片地图
  14. 程序员叫啥名字_什么是资深程序员?看自“配”的网名就真相了!
  15. 数据结构 —— 广义表
  16. 牛客编程巅峰赛S1第3场 - 黄金钻石 A.简单题 B.dfs C.并查集
  17. 初窥Xcode4 -- Xcode4主题样式、快捷键等常用设置
  18. 二开云海多功能解析系统全开源免授权4.5带插件
  19. win10 uwp 打开文件管理器选择文件
  20. BGP 基础与概述-2

热门文章

  1. AttributeError: 'NoneType' object has no attribute '__array_interface__'
  2. 第六章勘误以及Normalization算法不完整
  3. redis的各种数据集的列举功能
  4. 刪除github上的一個repository
  5. 禅道启动mysql报错_测试工具之在Linux服务器上部署禅道Bug管理系统
  6. 12036火车票小工具,希望大家都能顺利回家
  7. raid卡的结构示意图
  8. Puppet 的部署与应用,看这一篇就够了
  9. [转] C# TextBox、DataGrideView中的数据绑定
  10. 程序语言的奥妙:算法解读 ——读书笔记