Junit源码解析

本文深入解析JUnit的源码,从初始化阶段的TestRunner创建,测试驱动运行阶段的TestSuite构建与递归执行,到测试结果捕获。讲解了如何通过反射机制创建和运行测试方法,以及JUnit采用的Composite模式来组织测试集合。通过源码分析,了解JUnit如何执行测试并展示结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

程序运行顺序:

初始化阶段

JUnit的入口点在 junit.textui.TestRunner 的mian 方法,在这个方法中,首先创建一个 TestRunner 实例 aTestRunner ,然后 main 函数中主体工作函数调用了start()方法。

start()方法,首先对命令行参数进行解析:参数“ -wait ”(等待模式,测试完毕用户手动返回)、“ -c ”,“ -v ”(版本显示)。 -m 参数用于测试单个方法。这是 JUnit 提供给用户的一个非常轻便灵巧的测试功能,但是在一般情况下,用户会像本文前述那样在类名命令行参数。

 

  • 解析完参数,判断参数方法是否为空,如果不空执行runSingleMethod()。

代码流程:

  • runSingleMethod

runSingleMethod()方法,传入testCase,使用反射机制,初始化testCase的特定类,并且确定其类必须是testCase的子类。

然后调用TestSuite.createTest方法,同样使用反射机制,使用的testCase类的构造方法,创建test新实例并返回。

  • creatTest方法的实现方式

 

再然后进入核心流程:Test suite= getTest(testCase),初始化一个TestSuite对象,包含多个 TestCase测试方法用例。

TestSuite 的构造分两种情况:

  • A:用户在测试类中通过声明 Suite() 方法自定义 TestSuite 。

  • B:自动判断并提取 TestSuite

当 suite 方法未在 test case 中定义时,JUnit 自动分析创建一个 test suite 。代码由 :

1

return new TestSuite(testClass);

处进入 TestSuite(Class theclass) 。 TestSuite 类的构造方法,它能自动分析 theclass 所描述的类的内部有哪些方法需要测试,并加入到新构造的 TestSuite 中。代码如下:

TestSuite 采用了Composite(组合)模式。在该模式下,可以将 TestSuite 比作一棵树,树中可以包含子树(其它 TestSuite),也可以包含叶子 (TestCase),以此向下递归,直到底层全部落实到叶子为止。

JUnit 采用 Composite 模式维护测试集合的内部结构,使得所有分散的 TestCase 能够统一集中到一个或若干个 TestSuite 中,同类的 TestCase 在树中占据同等的位置,便于统一运行处理。另外,采用这种结构使测试集合获得了无限的扩充性,不需要重新构造测试集合,就能使新的 TestCase 不断加入到集合中。

有关组合模式的描述,请移步:常见的设计模式解析

addTestMethod是组合模式的关键实现部分,核心就是调用addTest(creatTest(theClass,name)); 可以理解成树结构的递归创建方式。

上面在runSingleMethod时候,解析到了createTest方法:

TestSuite 和 TestCase 都有一个fName实例变量,是在其后的测试运行及结果返回阶段中该 Test 的唯一标识,对 TestCase 来说,一般也是要测试的方法名。在 createTest 方法中,测试方法被转化成一个 TestCase 实例,并通过:

1

((TestCase) test).setName(name);

用该方法名标识 TestCase 。其中,test 对象也是通过 Refection 机制,通过 theClass 构建的:

1

test = constructor.newInstance(new Object[0]);

注意:theClass 是getTest 方法的 suiteClassName 字符串所构造的 Class 类实例,而后者其实是命令行参数传入的带测试类 Calculator,它继承了 TestCase 方法。因此,theClass 完全具备转化的条件。

至此整个流程的初始化完成。

 

测试驱动运行阶段(运行所有 TestXXX 型的测试方法)

初始化完毕,即 testsuit() 创建好后 , 便进入方法 :

1

doRun(suite, wait);

doRun(suite,wait)

doRun中调用了run()方法:TestSuite.run():

Junit 通过 for (Test each:fTests) 对 TestSuite 中的整个“树结构”递归遍历运行其中的节点和叶子。

 

下一步,解析run的核心方法,test.run(result).

TestCase 实现Test接口中的run方法:

只有在这里,用户测试方法的代码才开始被运行。

在测试方法运行时,众多的 Assert 方法会根据测试的实际情况,抛出失败异常或者错误。也是在“ runMethod.invoke(this, (Object[]) new Class[0]); ”这里,这些异常或错误往上逐层抛出,或者被某一层次处理,或者处理后再次抛出,依次递推,最终显示给用户。

流程图如下 :

JUnit 执行测试方法,并在测试结束后将失败和错误信息通知所有 test listener.

 

测试结果捕捉阶段(返回 Fail 或 Error 并显示)

 

待补充

----------------------------------------

参考资料:https://www.ibm.com/developerworks/cn/java/j-lo-junit-src/ 分析junit框架源代码,2009,何正华、徐晔

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值