技术开发 频道

分析 JUnit 框架源代码

  情况 B:

  图 10. 自动判断并提取 TestSuite 流程图  

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

 

  return new TestSuite(testClass);

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

  图 11. TestSuite 函数代码  

  TestSuite 采用了Composite 设计模式。在该模式下,可以将 TestSuite 比作一棵树,树中可以包含子树(其它 TestSuite),也可以包含叶子 (TestCase),以此向下递归,直到底层全部落实到叶子为止。 JUnit 采用 Composite 模式维护测试集合的内部结构,使得所有分散的 TestCase 能够统一集中到一个或若干个 TestSuite 中,同类的 TestCase 在树中占据同等的位置,便于统一运行处理。另外,采用这种结构使测试集合获得了无限的扩充性,不需要重新构造测试集合,就能使新的 TestCase 不断加入到集合中。

  在 TestSuite 类的代码中,可以找到:

 

  private Vector fTests = new Vector(10);

  此即为内部维护的“子树或树叶”的列表。

  红框内的代码完成提取整个类继承体系上的测试方法的提取。循环语句由 Class 类型的实例 theClass 开始,逐级向父类的继承结构追溯,直到优异 Object 类,并将沿途各级父类中所有合法的 testXXX() 方法都加入到 TestSuite 中。

  合法 testXXX 的判断工作由:

 

  addTestMethod(methods[i], names, theClass)

  完成,实际上该方法还把判断成功的方法转化为 TestCase 对象,并加入到 TestSuite 中。代码如下图 :

  图 12. addTestMethod 函数代码  

  首先通过 String name= m.getName(); 利用 Refection API 获得 Method 对象 m 的方法名,用于特征判断。然后通过方法

  isTestMethod(Method m)

  中的

 

  return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE);

  来判别方法名是不是以字符串“ test ”开始。

  而代码:  

if (names.contains(name))

  return;

  用于在逐级追溯过程中,防止不同级别父类中的 testXXX() 方法重复加入 TestSuite 。

  对于符合条件的 testXXX() 方法,addTestMethod 方法中用语句:

 

  addTest(createTest(theClass, name));

  将 testXXX 方法转化为 TestCase,并加入到 TestSuite 。其中,addTest 方法接受 Test 接口类型的参数,其内部有 countTestCases 方法和 run 方法,该接口被 TestSuite 和 TestCase 同时实现。这是 Command 设计模式精神的体现,

  Command 模式将调用操作的对象与如何实现该操作的对象解耦。在运行时,TestCase 或 TestSuite 被当作 Test 命令对象,可以像一般对象那样进行操作和扩展,也可以在实现 Composite 模式时将多个命令复合成一个命令。另外,增加新的命令十分容易,隔离了现有类的影响,今后,也可以与备忘录模式结合,实现 undo 等高级功能。

  加入 TestSuite 的 TestCase 由 createTest(theClass, name) 方法创建,代码如下:

  图 13. CreateTest 函数代码(查看大图)  

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

 

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

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

 

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

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

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

0
相关文章