程序运行顺序:
初始化阶段:
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 |
|
处进入 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 对象也是通过 Refection 机制,通过 theClass 构建的:
1 |
|
注意:theClass 是getTest 方法的 suiteClassName 字符串所构造的 Class 类实例,而后者其实是命令行参数传入的带测试类 Calculator,它继承了 TestCase 方法。因此,theClass 完全具备转化的条件。
至此整个流程的初始化完成。
测试驱动运行阶段(运行所有 TestXXX 型的测试方法)
初始化完毕,即 testsuit() 创建好后 , 便进入方法 :
1 |
|
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,何正华、徐晔