上一篇我们回答了之前在梳理流程时遇到的一些问题,并思考了为什么要这么设计。
本篇是《如何高效阅读源码》专题的第十二篇,通过项目之间的联系来进行扩展阅读,通过项目与项目之间的联系更好的理解项目。
本节内容:
-
TestRunner的执行流程
-
Spring如何整合JUnit
在我们使用Spring的项目中进行测试时,一般都需要添加下面一行注解:
@RunWith(SpringRunner.class
为什么要使用这个注解呢?为了回答这个问题,我们先来了解一下TestRunner是如何执行的。
TestRunner的执行流程在前面梳理的执行流程中,我们已经知道了JUnitCore是整个测试的入口,它构建了Runner实例,而Runner通过测试类构建了对应的测试模型,并通过Statement来执行,通过TestNotifier来通知TestListener来处理测试结果。
但是我们还没有梳理出JUnitCore是如何构建出Runner的,现在我们从JUnitCore入手,将最后一块拼图补全,梳理出一个完整的测试执行流程。
入口方法很简单,委托给了runMain方法来执行。
这里只是将命令行参数parse为一个对象,然后通过参数配置来执行测试。
注意到这里的addListener了吗?这里构建了一个TextListener,通过addListener添加到了TestNotifier中。前面我们已经知道,测试结果是通过TestNotifier来通知TestListener的,而这里就是向TestNotifier中添加TestListener实例的。这里就补齐了前面流程中缺的一块拼图。
最后一行通过createRequest方法构建了一个Request来执行测试
这里的run方法就是构建了基本的测试执行流程,调用了runner对象的run方法来执行具体的测试。前面我们已经梳理了TestRunner的方法的具体流程,这里就将我们前面梳理的流程完整的串联起来了。
注意上面的request.getRunner,现在我们只需要梳理出Request是如何获取到runner的,那么整个执行流程就完整了。
让我们回过头来看createRequest方法。
这里通过Request的静态方法classes来构建Request。
这里构建了一个AllDefaultPossibilitiesBuilder实例,通过builder实例来构建Runner。篇幅限制,我们就直接到AllDefaultPossibilitiesBuilder的runnerForClass方法,来看看builder是怎么构建Runner的。
首先,构建了5个默认的RunnerBuilder,然后通过对应的RunnerBuilder来构建Runner,如果构建成功了,则直接返回对应的Runner去执行测试。
注意最后一个builder方法junit4Builder,从名字我们可以知道它是用来构建JUnit4Runner的,我们点进去确认一下。
的确是创建JUnit4对象的。
至此,我们整个的执行流程就梳理出来了:
-
JUnitCore根据参数,通过Request和Builder构建了对应的Runner实例
-
Runner通过测试类构建了对应的测试模型,并通过Statement来执行,通过TestNotifier来通知TestListener来处理测试结果
上面的流程和Spring整合JUnit有什么关系呢?
前面我们知道Spring测试需要添加一个注解RunWith,我们注意上面的builder方法,其中有个builder方法是annotatedBuilder,我们来看这个方法。
此方法通过RunWith注解,找到了对应的类,然后进行了实例化,作为Runner进行返回。注意上面AllDefaultPossibilitiesBuilder的runnerForClass方法的循环,如果找到了Runner就直接返回了,而annotatedBuilder是比较靠前的,所以获取到Runner后就不会再执行后面的builder了。Spring中就是使用SpringRunner来执行测试了。
而SpringRunner又是如何执行测试的呢?结合前面梳理的Runner流程,你可以自己尝试去梳理看看。
总结本文通过Spring如何结合JUnit的例子梳理出了JUnit4完整的执行流程,以及梳理出Spring结合JUnit的方式。通过此方式讲述了如何通过关联延伸阅读将多个项目整合起来,更好的理解项目之间的关系。
下文将讲解不同版本之间源码的阅读。
公众号:一瑜一琂