我们先看下ClassTestDescriptor所构成的NodeTestTask的执行流程,执行before方法,跳转到父类ClassBasedTestDescriptor 里面执行
public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) {//查找新的Extension, 这里才注册SpringExtensionMutableExtensionRegistry registry = populateNewExtensionRegistryFromExtendWithAnnotation(context.getExtensionRegistry(), this.testClass);// Register extensions from static fields here, at the class level but// after extensions registered via @ExtendWith.//查找filed 域的扩展,如被注解 @RegisterExtension 修饰的属性registerExtensionsFromFields(registry, this.testClass, null);// Resolve the TestInstanceFactory at the class level in order to fail// the entire class in case of configuration errors (e.g., more than// one factory registered per class).//当前为null, 跳过this.testInstanceFactory = resolveTestInstanceFactory(registry);//注册 被注解BeforeEach 修饰的方法,在我们当前举得例子中,是基类BaseTest中的init方//这里注册的是 BeforeEachMethodAdapter ExtensioregisterBeforeEachMethodAdapters(registry);//注册 被注解AfterEach 修饰的方法registerAfterEachMethodAdapters(registry);ThrowableCollector throwableCollector = createThrowableCollector();ClassExtensionContext extensionContext = new ClassExtensionContext(context.getExtensionContext(),context.getExecutionListener(), this, this.lifecycle, context.getConfiguration(), throwableCollector);//通过注解查找beforeAll方法this.beforeAllMethods = findBeforeAllMethods(this.testClass, this.lifecycle == Lifecycle.PER_METHOD);//通过注解查找afterAll方法this.afterAllMethods = findAfterAllMethods(this.testClass, this.lifecycle == Lifecycle.PER_METHOD);//刷新contextreturn context.extend()//这里是个关键流程,注册了TestInstancesProvider,为后面初始化testInstance做准备.withTestInstancesProvider(testInstancesProvider(context, extensionContext)).withExtensionRegistry(registry).withExtensionContext(extensionContext).withThrowableCollector(throwableCollector).build();// @formatter:on}//lambda初始化TestInstancesProvider接口实现类private TestInstancesProvider testInstancesProvider(JupiterEngineExecutionContext parentExecutionContext,ClassExtensionContext extensionContext) {return (registry, registrar) -> extensionContext.getTestInstances().orElseGet(() -> instantiateAndPostProcessTestInstance(parentExecutionContext, extensionContext, registry, registrar));}private TestInstances instantiateAndPostProcessTestInstance(JupiterEngineExecutionContext parentExecutionContext,ExtensionContext extensionContext, ExtensionRegistry registry, ExtensionRegistrar registrar) {......}
执行完prepare方法后,在executeRecursively方法中继续执行node.before方法
public JupiterEngineExecutionContext before(JupiterEngineExecutionContext context) {ThrowableCollector throwableCollector = context.getThrowableCollector();......if (throwableCollector.isEmpty()) {context.beforeAllCallbacksExecuted(true);//执行beforeAllCallBack方法,在这里初始化TestContextManagerinvokeBeforeAllCallbacks(context);if (throwableCollector.isEmpty()) {context.beforeAllMethodsExecuted(true);//执行beforeAll 方法invokeBeforeAllMethods(context);}}......return context;}......private void invokeBeforeAllCallbacks(JupiterEngineExecutionContext context) {......for (BeforeAllCallback callback : registry.getExtensions(BeforeAllCallback.class)) {//实现BeforeAllCallback的实现类主要有TimeOUtExtension,SpringExtension, TempDirectory, OutputCaptureExtension//这里我们主要关注SpringExtension 相关的处理方法throwableCollector.execute(() -> callback.beforeAll(extensionContext));if (throwableCollector.isNotEmpty()) {break;}}}//SpringExtension的beforeAll方法public void beforeAll(ExtensionContext context) throws Exception {getTestContextManager(context).beforeTestClass();}
在SpringExtension的beforeAll方法中,初始化了TestContextManager对象,循环遍历TestExecutionListener,执行listener的beforeTestClass方法
这里涉及到了Spring TestContext Framework机制,详细机制讲解可见官方文档
https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html#testcontext-framework
/*** Get the {@link TestContextManager} associated with the supplied {@code ExtensionContext}.* @return the {@code TestContextManager} (never {@code null})*/private static TestContextManager getTestContextManager(ExtensionContext context) {Assert.notNull(context, "ExtensionContext must not be null");Class<?> testClass = context.getRequiredTestClass();//获取当前的ExtensionContext中的ExtensionValuesStore对象valuesStoreStore store = getStore(context);//存在则获取Supplier<Object> storedValue, 里面是个creator function, 通过storedValue.get()执行function创建return store.getOrComputeIfAbsent(testClass, TestContextManager::new, TestContextManager.class);}......<K, V> Object getOrComputeIfAbsent(Namespace namespace, K key, Function<K, V> defaultCreator) {//通过namespacce和 testClass 构造compositeKeyCompositeKey compositeKey = new CompositeKey(namespace, key);Supplier<Object> storedValue = getStoredValue(compositeKey);if (storedValue == null) {//构造Supplier 对象,MemoizingSupplier为Supplier的扩展,增加了锁机制Supplier<Object> newValue = new MemoizingSupplier(() -> defaultCreator.apply(key));storedValue = Optional.ofNullable(storedValues.putIfAbsent(compositeKey, newValue)).orElse(newValue);}//执行defaultCreator.apply(key),即执行public TestContextManager(Class<?> testClass) 方法,创建TestContextManager对象return storedValue.get();}<K, V> V getOrComputeIfAbsent(Namespace namespace, K key, Function<K, V> defaultCreator, Class<V> requiredType) {Object value = getOrComputeIfAbsent(namespace, key, defaultCreator);return castToRequiredType(key, value, requiredType);}
初始化TestContextManager过程中,会初始化TestContextBootstrapper对象,会查找@BootstrapWith的value值并初始化,我们可以看到查找到@SpringBootTest时候会初始化SpringBootTestContextBootstrapper对象
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@BootstrapWith(SpringBootTestContextBootstrapper.class)@ExtendWith(SpringExtension.class)public @interface SpringBootTest {......}
在构造方法中,会构造TestContext对象
//主要构造方法,生成TestContext 对象,注册执行监听器public TestContextManager(TestContextBootstrapper testContextBootstrapper) {this.testContext = testContextBootstrapper.buildTestContext();//注册发现的监听器,即加入一个TestExecutionListener链表registerTestExecutionListeners(testContextBootstrapper.getTestExecutionListeners());}
在buildTestContext()方法中,构造了TestContext 对象,其中会调用父类AbstractTestContextBootstrapper抽象类中的build方法,父类方法主要构造了WebMergedContextConfiguration对象(其中很多查询不同注解生成不同配置的细节,感兴趣同学可以自行阅读),最后通过构造方法生成DefaultTestContext对象
/*** Construct a new {@code DefaultTestContext} from the supplied arguments.* @param testClass the test class for this test context* @param mergedContextConfiguration the merged application context* configuration for this test context* @param cacheAwareContextLoaderDelegate the delegate to use for loading* and closing the application context for this test context*/public DefaultTestContext(Class<?> testClass, MergedContextConfiguration mergedContextConfiguration,CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate) {......this.testClass = testClass;this.mergedContextConfiguration = mergedContextConfiguration;this.cacheAwareContextLoaderDelegate = cacheAwareContextLoaderDelegate;}
在getTestExecutionListeners() 方法中获取默认的TestExecutionListener列表,里面通过spi机制会加载配置文件中的listenner, 同时通过监听器后置处理方法 用SpringBootDependencyInjectionTestExecutionListener替换掉DependencyInjectionTestExecutionListener
public Set<Class<? extends TestExecutionListener>> postProcessDefaultTestExecutionListeners(Set<Class<? extends TestExecutionListener>> listeners) {Set<Class<? extends TestExecutionListener>> updated = new LinkedHashSet<>(listeners.size());for (Class<? extends TestExecutionListener> listener : listeners) {//springboot中使用新的监听器替换掉spring使用的DependencyInjectionTestExecutionListenerupdated.add(listener.equals(DependencyInjectionTestExecutionListener.class)? SpringBootDependencyInjectionTestExecutionListener.class : listener);}return updated;}
以上流程执行完成node.before方法,接下来执行node.execute方法,当前node为ClassTestDescriptor,execute方法为空直接跳过;执行到子node节点时,通过执行taskContext.getExecutorService().invokeAll(children)方法执行子 node即TestMethodTestDescriptor。
TestMethodTestDescriptor 中的prepare方法,会调用父context中的TestInstancesProvider初始化TestInstances
public JupiterEngineExecutionContext prepare(JupiterEngineExecutionContext context) {MutableExtensionRegistry registry = populateNewExtensionRegistry(context);ThrowableCollector throwableCollector = createThrowableCollector();MethodExtensionContext extensionContext = new MethodExtensionContext(context.getExtensionContext(),context.getExecutionListener(), this, context.getConfiguration(), throwableCollector);throwableCollector.execute(() -> {//获取ClassTestDescriptor 中注册的Provider并实例TestInstances testInstances = context.getTestInstancesProvider().getTestInstances(registry);extensionContext.setTestInstances(testInstances);});// @formatter:offreturn context.extend().withExtensionRegistry(registry).withExtensionContext(extensionContext).withThrowableCollector(throwableCollector).build();// @formatter:on}
调用ClassBasedTestDescriptor 中的instantiateTestClass实例化TestInstances
private TestInstances instantiateAndPostProcessTestInstance(JupiterEngineExecutionContext parentExecutionContext,ExtensionContext extensionContext, ExtensionRegistry registry, ExtensionRegistrar registrar) {//初始化测试用例实例TestInstances instances = instantiateTestClass(parentExecutionContext, registry, registrar, extensionContext);invokeTestInstancePostProcessors(instances.getInnermostInstance(), registry, extensionContext);// In addition, we register extensions from instance fields here since the// best time to do that is immediately following test class instantiation// and post processing.registerExtensionsFromFields(registrar, this.testClass, instances.getInnermostInstance());return instances;}......protected TestInstances instantiateTestClass(Optional<TestInstances> outerInstances, ExtensionRegistry registry,ExtensionContext extensionContext) {Optional<Object> outerInstance = outerInstances.map(TestInstances::getInnermostInstance);Object instance = this.testInstanceFactory != null //? invokeTestInstanceFactory(outerInstance, extensionContext)//通过构造方法初始化: invokeTestClassConstructor(outerInstance, registry, extensionContext);return outerInstances.map(instances -> DefaultTestInstances.of(instances, instance)).orElse(//返回DefaultTestInstances对象DefaultTestInstances.of(instance));}
invokeTestInstancePostProcessors 方法中,会调用TestInstancePostProcessor接口的实现类中的postProcessTestInstance方法,前实现类有MockitoExtension和SpringExtension
private void invokeTestInstancePostProcessors(Object instance, ExtensionRegistry registry,ExtensionContext context) {registry.stream(TestInstancePostProcessor.class).forEach(extension -> executeAndMaskThrowable(() -> extension.postProcessTestInstance(instance, context)));}
1)在SpringExtension中的实现方法调用prepareTestInstance方法初始化容器,启动springboot。具体执行流程为:
在prepareTestInstance方法中,遍历testExecutionListeners,依次为ServletTestExecutionListener,其中会初始化加载ApplicationContext,具体在DefaultTestContext对象中查找CacheAwareContextLoaderDelegate对象中的ContextCache,通过前面构建的MergedContextConfiguration key查找对应的ApplicationContext, 不存在通过SmartContextLoader即SpringBootContextLoader加载,最后调用SpringApplication.run方法启动SpringBoot
private void setUpRequestContextIfNecessary(TestContext testContext) {if (!isActivated(testContext) || alreadyPopulatedRequestContextHolder(testContext)) {return;}//加载ApplicationContext,过程中启动SpringBootApplicationContext context = testContext.getApplicationContext();......}
2)在MockitoTestExecutionListener中,查找测试类中的org.mockito开头的注解,如@Mock等,
public void prepareTestInstance(TestContext testContext) throws Exception {//查找org.mockito库中注解修饰的属性并初始化//使用mokito库构造注解对象,并注入到对应测试类testInstance中的mock相关属性initMocks(testContext);//注入mock的属性,这里注入的是springboot 下的mockbean, spybean等注解修饰的属性injectFields(testContext);}......private void postProcessFields(TestContext testContext, BiConsumer<MockitoField, MockitoPostProcessor> consumer) {DefinitionsParser parser = new DefinitionsParser();//前面构建MergedContextConfiguration 过程中会解析一遍,当前重新解析parser.parse(testContext.getTestClass());if (!parser.getDefinitions().isEmpty()) {//获取MockitoPostProcessor beanMockitoPostProcessor postProcessor = testContext.getApplicationContext().getBean(MockitoPostProcessor.class);for (Definition definition : parser.getDefinitions()) {Field field = parser.getField(definition);if (field != null) {//注入MockitoFieldconsumer.accept(new MockitoField(field, testContext.getTestInstance(), definition), postProcessor);}}}}
3)在 SpringBootDependencyInjectionTestExecutionListener 中,通过injectDependencies方法依赖注入,给testInstance中的其他非mock属性注入对应的值,这里使用的autowireMode 为 AutowireCapableBeanFactory.AUTOWIRE_NO
private TestInstances instantiateAndPostProcessTestInstance(JupiterEngineExecutionContext parentExecutionContext,ExtensionContext extensionContext, ExtensionRegistry registry, ExtensionRegistrar registrar) {TestInstances instances = instantiateTestClass(parentExecutionContext, registry, registrar, extensionContext);invokeTestInstancePostProcessors(instances.getInnermostInstance(), registry, extensionContext);// In addition, we register extensions from instance fields here since the// best time to do that is immediately following test class instantiation// and post processing.registerExtensionsFromFields(registrar, this.testClass, instances.getInnermostInstance());return instances;}
testInstance实例化完成后,返回到TestMethodTestDescriptor中,设置好MethodExtensionContext中testInstances的值。
下节将继续讲解TestMethodTestDescriptor的execute方法。
To be continued...




