Junit源码分析

 

junit是我们平时开发中天天用到的测试框架,为了了解器内部隐藏的机关,特意分析了一下源码,这里我们用的是Junit3.8版本。

1.包的划分

《Junit源码分析》

  junit.awtui,这个是junit的awt实现的ui界面组件

  junit.extensions这个是junit核心功能之外的扩展点,对TestCase的装饰,Demorator模式的很好的例子

  junit.framework,这个是junit的核心功能,像我们平时常用的TestCase,TestSuit类都是在这的,还有Assert类,提供了我们测试中常用的断言静态方法

  junit.runner,这个包下是运行TestCase的核心类,最重要的是TestListener和BaseTestRunner类,这个后面会解释到

  junit.swingui,这个包的作用和junit.awtui是完全一直的,只不过是用Swing的方式实现而已

  junit.textui,功能等价与junit.awtui和junit.swingui,junit控制台输出的一个实现,下面的源码解读中,我们以textui包作为ui输出解释

  从上面的分析可以看出,Junit运行的最小单元是framework+runner+ui-简洁就是美

2.框架的核心类

  junit的源码非常小,但是设计的非常巧妙,核心类/接口大约有5-6个的样子,通过分析,我们可以得出一下的核心类图

《Junit源码分析》

  Test接口:这个是最顶层的测试实体抽象,接口中只定义了两个方法,countTestCases()表示当前测试实体有多少个测试用例,另一个就是核心的run方法了

  TestCase类–Test接口的一个实现类,也是我们平时常用的测试父类,表示一个要进行测试的对象,在实际代码中,代表我们一个个的测试方法(junit3.8中只那些继承了TestCase类中那些以test开头的测试方法)

  TestSuit类–Test接口的另一个实现,见名知其意,是一组测试用例类,和TestCase是一对多关系

  TestResult类-这个是测试结果的包裹类,提供了常用的方法,如测试失败时,测试成功时做一些处理,基于Observer模式实现

  TestListener接口–整个junit核心基于ObserVer模式实现,这个接口则是对Observer的抽象

  BaseTestRunner类–TestListener的抽象实现,定义了通用的公共方法,而TestRunner(swing,atw,textui)则是扩展了基类的功能,提供了ui的展示层功能

2.源码解读

  上面介绍了框架的核心类,接下来看下我们的核心类之间如何协调来完成测试的

《Junit源码分析》

3.junit的设计思想

  3.1观察者模式

     观察者模式的核心对象有两个,一个是要监控的对象,junit里就是一个个测试用例TestCase,另一个是观察者,当监控对象发生变化时(测试用例开始前,出错,运行失败,运行结束事件),做出一些操作(GUI更新)。从第一节的类层次中可以看出,junit本身对TestListener做了封装,上层可以通过继承这个类来快速的开发出另一种观察者的实现,如我们在Eclipse中运用junit插件,其实就是插件中扩展一下BaseTestRunner的功能,增加eclipse展示的ui而已,而底层的核心逻辑是不需要变化的

  3.2模板方法模式

     可以这样理解模板方法模式,在父类中定义一个算法的骨架,而具体的实现类则放在子类中去实现,junit很多地方都充斥着这种思想

     TestTest.run方法就是一个模板方法startTest,runTest,endTest,依次执行,我们熟知的TestCase中,每个测试方法执行前都会运行setUp,测试方法运行完后运行tearDown方法,这个也是个模板方法模式的实现,在TestCase中有个我们不直接调的核心模板方法

/** * Runs a TestCase. */ protected void run(final TestCase test) { startTest(test); Protectable p= new Protectable() { public void protect() throws Throwable { test.runBare(); } }; runProtected(test, p); endTest(test); }  这下子搞明白了,这个方法则是在更顶层的TestResult.run中调用runBare(),然后runBare()中调用我们熟知的那些setUp,tearDown 3.3约定大于配置      测试junit3测试用例的同学都知道,要写一个让junit可以运行的测试用例,我们的测试方法必须是public void test***()这种格式的,否则junit不会执行,为什么呢?看下junit的实现细节 private void addTestMethod(Method m, Vector names, Class theClass) { String name= m.getName(); if (names.contains(name)) return; if (! isPublicTestMethod(m)) { if (isTestMethod(m)) addTest(warning(“Test method isn’t public: “+m.getName())); return; } names.addElement(name); addTest(createTest(theClass, name)); } private boolean isTestMethod(Method m) { String name= m.getName(); Class[] parameters= m.getParameterTypes(); Class returnType= m.getReturnType(); return parameters.length == 0 && name.startsWith(“test”) && returnType.equals(Void.TYPE);//这个地方判断方法以test开头是写死的:) }        这种做法有两种争论,一种是支持派,有这样一个约定,大家都没的选,样式统一规范,看一眼就知道是个测试方法,这种方式和maven项目的默认项目结构有点类似–要到这个山头混,就得听山大王的:)      另一种是反对派,认为这种方式太过死板,为什么测试方法不可以有参数,为什么不能不以test开头,这可能也是后来testgn,junit4横空出世的原因吧:) 4.收获&总结      一个优秀的框架不在于它有多大,内部用了多先进的技术,用最简单的东西实现最常用的功能就可以了,研究源码主要收获如下      1).系统设计(特别是框架设计)一定要简洁易懂,简洁就是美      2).为系统设计留有余地–系统的内核在于定义核心逻辑和算法,但是具体实现的多样化可以留给后来人自由扩展–对接口和抽象编程,定义钩子方法..

 

 

 

 

    原文作者:java简单例子
    原文地址: http://www.cnblogs.com/javaexam2/archive/2011/03/16/2632561.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞