org.springframework.test.context.junit4.SpringJUnit4ClassRunner
spring 的单元测试是如何复用容器的1、创建runner执行器此时初始化的TestContextManager 中并没有上下文容器信息org.springframework.test.context.junit4.SpringJUnit4ClassRunner#createTestContextManagerpublic SpringJUnit4ClassRunner(Class<?&g
·
spring 的单元测试是如何复用容器的
1、创建runner执行器
此时初始化的TestContextManager 中并没有上下文容器信息
org.springframework.test.context.junit4.SpringJUnit4ClassRunner#createTestContextManager
public SpringJUnit4ClassRunner(Class<?> clazz) throws InitializationError {
super(clazz);
if (logger.isDebugEnabled()) {
logger.debug("SpringJUnit4ClassRunner constructor called with [" + clazz + "]");
}
ensureSpringRulesAreNotPresent(clazz);
this.testContextManager = createTestContextManager(clazz);
}
这部分不做赘述 可以参考
单元测试-junit
org.junit.runner.Runner#run
2、创建子任务
org.springframework.test.context.junit4.SpringJUnit4ClassRunner#methodBlock
@Override
protected Statement methodBlock(FrameworkMethod frameworkMethod) {
Object testInstance;
try {
testInstance = new ReflectiveCallable() {
@Override
protected Object runReflectiveCall() throws Throwable {
return createTest();
}
}.run();
}
catch (Throwable ex) {
return new Fail(ex);
}
Statement statement = methodInvoker(frameworkMethod, testInstance);
statement = withBeforeTestExecutionCallbacks(frameworkMethod, testInstance, statement);
statement = withAfterTestExecutionCallbacks(frameworkMethod, testInstance, statement);
statement = possiblyExpectingExceptions(frameworkMethod, testInstance, statement);
statement = withBefores(frameworkMethod, testInstance, statement);
statement = withAfters(frameworkMethod, testInstance, statement);
statement = withRulesReflectively(frameworkMethod, testInstance, statement);
statement = withPotentialRepeat(frameworkMethod, testInstance, statement);
statement = withPotentialTimeout(frameworkMethod, testInstance, statement);
return statement;
}
protected Object createTest() throws Exception {
Object testInstance = super.createTest();
getTestContextManager().prepareTestInstance(testInstance);
return testInstance;
}
3、初始化容器信息
org.springframework.test.context.TestContextManager#prepareTestInstance
public void prepareTestInstance(Object testInstance) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("prepareTestInstance(): instance [" + testInstance + "]");
}
getTestContext().updateState(testInstance, null, null);
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
try {
testExecutionListener.prepareTestInstance(getTestContext());
}
catch (Throwable ex) {
if (logger.isErrorEnabled()) {
logger.error("Caught exception while allowing TestExecutionListener [" + testExecutionListener +
"] to prepare test instance [" + testInstance + "]", ex);
}
ReflectionUtils.rethrowException(ex);
}
}
}
org.springframework.test.context.support.DependencyInjectionTestExecutionListener#prepareTestInstance
protected void injectDependencies(TestContext testContext) throws Exception {
Object bean = testContext.getTestInstance();
Class<?> clazz = testContext.getTestClass();
AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext().getAutowireCapableBeanFactory();
beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
beanFactory.initializeBean(bean, clazz.getName() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX);
testContext.removeAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE);
}
4、实例化上线文
org.springframework.test.context.support.DefaultTestContext#getApplicationContext
org.springframework.test.context.CacheAwareContextLoaderDelegate#loadContext
public ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) {
synchronized (this.contextCache) {
ApplicationContext context = this.contextCache.get(mergedContextConfiguration);
if (context == null) {
try {
context = loadContextInternal(mergedContextConfiguration);
if (logger.isDebugEnabled()) {
logger.debug(String.format("Storing ApplicationContext in cache under key [%s]",
mergedContextConfiguration));
}
this.contextCache.put(mergedContextConfiguration, context);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to load ApplicationContext", ex);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Retrieved ApplicationContext from cache with key [%s]",
mergedContextConfiguration));
}
}
this.contextCache.logStatistics();
return context;
}
}
org.springframework.test.context.cache.DefaultContextCache 缓存管理
private final Map<MergedContextConfiguration, ApplicationContext> contextMap =
Collections.synchronizedMap(new LruCache(32, 0.75f));
org.springframework.test.context.MergedContextConfiguration 容器是否相同识别的对象 重写了hashCode和equals
public int hashCode() {
int result = Arrays.hashCode(this.locations);
result = 31 * result + Arrays.hashCode(this.classes);
result = 31 * result + this.contextInitializerClasses.hashCode();
result = 31 * result + Arrays.hashCode(this.activeProfiles);
result = 31 * result + Arrays.hashCode(this.propertySourceLocations);
result = 31 * result + Arrays.hashCode(this.propertySourceProperties);
result = 31 * result + this.contextCustomizers.hashCode();
result = 31 * result + (this.parent != null ? this.parent.hashCode() : 0);
result = 31 * result + nullSafeClassName(this.contextLoader).hashCode();
return result;
}
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (other == null || other.getClass() != getClass()) {
return false;
}
MergedContextConfiguration otherConfig = (MergedContextConfiguration) other;
if (!Arrays.equals(this.locations, otherConfig.locations)) {
return false;
}
if (!Arrays.equals(this.classes, otherConfig.classes)) {
return false;
}
if (!this.contextInitializerClasses.equals(otherConfig.contextInitializerClasses)) {
return false;
}
if (!Arrays.equals(this.activeProfiles, otherConfig.activeProfiles)) {
return false;
}
if (!Arrays.equals(this.propertySourceLocations, otherConfig.propertySourceLocations)) {
return false;
}
if (!Arrays.equals(this.propertySourceProperties, otherConfig.propertySourceProperties)) {
return false;
}
if (!this.contextCustomizers.equals(otherConfig.contextCustomizers)) {
return false;
}
if (this.parent == null) {
if (otherConfig.parent != null) {
return false;
}
}
else if (!this.parent.equals(otherConfig.parent)) {
return false;
}
if (!nullSafeClassName(this.contextLoader).equals(nullSafeClassName(otherConfig.contextLoader))) {
return false;
}
return true;
}
如果我们的容器一直触发重复启动的话可以来这地方看一下 是否每个单测类定制的特殊情况影响到了缓存的识别逻辑 导致缓存未生效。
更多推荐
已为社区贡献2条内容
所有评论(0)