测试代码
package org.simonme.srcstudy.spring3.demo.stub; import static org.junit.Assert.assertNotNull; import org.junit.Test; import org.junit.runner.RunWith; import org.simonme.srcstudy.spring3.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * <一句话功能简述> * <功能详细描述> * * @author http://www.cnblogs.com/simoncook * @version [版本号, 2017年11月4日] * @see [相关类/方法] * @since [产品/模块版本] */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"/applicationContext.xml"}) public class UserServiceAssemblyByJUnit { private UserService userService; @Test public void test() { assertNotNull(userService); } public UserService getUserService() { return userService; } @Autowired public void setUserService(UserService userService) { this.userService = userService; } |
分析方式
this.userService = userService; 这一行直接断点
堆栈信息
org.simonme.srcstudy.spring3.demo.stub.UserServiceAssemblyByJUnit.setUserService(org.simonme.srcstudy.spring3.demo.service.UserService) line: 50 sun.reflect.NativeMethodAccessorImpl.invoke0(java.lang.reflect.Method, java.lang.Object, java.lang.Object[]) line: not available [native method] sun.reflect.NativeMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) line: 39 sun.reflect.DelegatingMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) line: 25 java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object...) line: 597 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(java.lang.Object, java.lang.String, org.springframework.beans.PropertyValues) line: 582 org.springframework.beans.factory.annotation.InjectionMetadata.inject(java.lang.Object, java.lang.String, org.springframework.beans.PropertyValues) line: 84 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(org.springframework.beans.PropertyValues, java.beans.PropertyDescriptor[], java.lang.Object, java.lang.String) line: 282 org.springframework.beans.factory.support.DefaultListableBeanFactory(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory).populateBean(java.lang.String, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.BeanWrapper) line: 1074 org.springframework.beans.factory.support.DefaultListableBeanFactory(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory).autowireBeanProperties(java.lang.Object, int, boolean) line: 374 org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(org.springframework.test.context.TestContext) line: 110 org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(org.springframework.test.context.TestContext) line: 75 org.springframework.test.context.TestContextManager.prepareTestInstance(java.lang.Object) line: 321 org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest() line: 220 org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall() line: 301 org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1(org.junit.internal.runners.model.ReflectiveCallable).run() line: 12 org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(org.junit.runners.model.FrameworkMethod) line: 303 org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(org.junit.runners.model.FrameworkMethod, org.junit.runner.notification.RunNotifier) line: 240 org.springframework.test.context.junit4.SpringJUnit4ClassRunner(org.junit.runners.BlockJUnit4ClassRunner).runChild(java.lang.Object, org.junit.runner.notification.RunNotifier) line: 50 org.junit.runners.ParentRunner$3.run() line: 238 org.junit.runners.ParentRunner$1.schedule(java.lang.Runnable) line: 63 org.springframework.test.context.junit4.SpringJUnit4ClassRunner(org.junit.runners.ParentRunner<T>).runChildren(org.junit.runner.notification.RunNotifier) line: 236 org.junit.runners.ParentRunner<T>.access$000(org.junit.runners.ParentRunner, org.junit.runner.notification.RunNotifier) line: 53 org.junit.runners.ParentRunner$2.evaluate() line: 229 |
看junit的运作方式
从main方法到runner
翻看官方guide 很容易发现JUnitCore是main方法所在类
JUnitCore是如何到runner的呢? 看下面分析
org.junit.runner.JUnitCore.main(String...) // 一些listener构造之类,然后通过AllDefaultPossibilitiesBuilder 构建runner org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(Class<?>) List<RunnerBuilder> builders = Arrays.asList( ignoredBuilder(), annotatedBuilder(), suiteMethodBuilder(), junit3Builder(), junit4Builder()); for (RunnerBuilder each : builders) { Runner runner = each.safeRunnerForClass(testClass); if (runner != null) { return runner; } } |
找到一个就直接返回
ignoredBuilder 可以用过Ignore注解忽略你的test case
annotatedBuilder 是找 RunWith注解定义的自定义runner
junit3Builder 如果test case 继承自TestCase类 则用junit3的runner
junit4Builder 直接对接 BlockJUnit4ClassRunner
spring的SpringJUnit4ClassRunner也是继承自BlockJUnit4ClassRunner
回头去看上面的堆栈信息 一目了然
关键点在于重写 org.junit.runners.BlockJUnit4ClassRunner.createTest() 这个方法
protected Object createTest() throws Exception { return getTestClass().getOnlyConstructor().newInstance(); } /** * Delegates to the parent implementation for creating the test instance and * then allows the {@link #getTestContextManager() TestContextManager} to * prepare the test instance before returning it. * * @see TestContextManager#prepareTestInstance(Object) */ @Override protected Object createTest() throws Exception { Object testInstance = super.createTest(); getTestContextManager().prepareTestInstance(testInstance); return testInstance; } |
也就是把JUnit原生的创建test case的instance的过程接用spring容器装配的方式接管过来就可以了。
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。