1. 工作原理
在 JUnit 初始化时,会调用 RunnerBuilder 将测试类 testClass 包装成 Runner,最后调用 Runner#run 方法执行单元测试。不用说,你也猜到,肯定是先扫描该类上有 @Test 注解的方法,然后调用方法的反射一一执行。 总结:JUnit 可以分为两个阶段。
- 初始化阶段:调用 RunnerBuilder 构建 Runner,本质是扫描有 @Test 注解的方法包装成 FrameworkMethod。
- 执行阶段:调用 Runner#run 时,通过方法的反射执行。
2. 源码分析
2.1 RunnerBuilder
org.junit.internal.builders 包下,JUnit 对外提供 AllDefaultPossibilitiesBuilder 作为构建 Runner 的方式,默认提供了以下 5 种方式。AllDefaultPossibilitiesBuilder
-> IgnoredBuilder // 1. @Ignored,对应IgnoredClassRunner
-> AnnotatedBuilder // 2. @RunWith,对应RunWith.value值
-> SuiteMethodBuilder // 3. 测试类有suit方法,对应SuiteMethod
-> JUnit3Builder // 4. JUnit 3(TestCase),对应JUnit38ClassRunner
-> JUnit4Builder // 5. JUnit 4(@Test),对应BlockJUnit4ClassRunner
2.2 Runner
Runner 是 JUnit 的核心,它封装了一个测试类中所有的测试方法,如 BlockJUnit4ClassRunner,或者是多个 Runner,如 Suite。上述 5 种 Runner,我们会重点介绍一下 AnnotatedBuilder 和 JUnit4Builder。2.2.1 JUnit38ClassRunner
JUnit38ClassRunner 用于处理 TestCase 测试类,可以参考《JUnit之TestCase和TestSuite详解》。
使用 JUnit38ClassRunner 时,有两个要求(具体代码见 TestSuite#isTestMethod):
- 一是测试类需要继承 TestCase;
- 二是测试方法名以 test 开头。
public class MyTestCase extends TestCase {
public void testMethod1() {
}
}
2.2.2 AnnotatedBuilder
AnnotatedBuilder 处理 @RunWith 注解,具有很好的扩展性,比如 SpringRunner 扩展。如果测试类上标注有 @RunWith 注解,AnnotatedBuilder#runnerForClass 方法会读取该标注的 Runner 类处理该测试类。@RunWith(SpringRunner.class)
public class MyTest {
}
2.2.3 BlockJUnit4ClassRunner
通常,如果测试类没有 @RunWith 注解,基本上就是 BlockJUnit4ClassRunner 来处理的。BlockJUnit4ClassRunner 其实也很简单:
- 初始化阶段:调用 scanAnnotatedMembers 方法扫描该没测试类的 @BeforeClass、@AfterClass、@Before、@After、@Test、@Ignore 注解。
执行阶段:将所有标注 @Test 的方法包装成 InvokeMethod,通过反射执行。调用链如下:
ParentRunner#run
-> classBlock // 创建 Class Statement
-> childrenInvoker
-> withBeforeClasses // @BeforeClass
-> withAfterClasses // @AfterClass
-> Statement#evaluate
-> runChildren
-> getChildren // @Test
-> BlockJUnit4ClassRunner#runChild
BlockJUnit4ClassRunner#runChild
-> methodBlock // 创建 Method Statement
-> methodInvoker
-> withBefores // @Before
-> withAfters // @After
-> Statement#evaluate
-> InvokeMethod#evaluate // 反射执行
3. 总结时刻
推荐阅读
《JUnit 5 新特性》IBM
- 《有赞测试 有赞单元测试实践》
每天用心记录一点点。内容也许不重要,但习惯很重要!