浅读JUnit源码

       为了学习下设计模式在实际项目中的应用,我决定找个开源项目来研究下,JUnit代码量少,又是GOF的亲生儿子,当然成了最佳选择。我阅读的是JUnit3.8.2的代码,相对于JUnit4,JUnit3的代码量更小,结构更清楚。

准备工作及JUnit基本用法

下载JUnit源代码,在Eclipse中新建项目,并导入下载的JUnit代码。下载地址为:http://grepcode.com/snapshot/repo1.maven.org/maven2/junit/junit/3.8.2

定义被测试代码。这里的被测试代码很简单,就是计算两个整数之和。

package my.test;

public class SimpleClass {

    public static int add(int a, int b) {
        return a + b;
    }
}

接下来写测试用例。JUnit测试用例可以通过继承junit.framework.TestCase类来实现。一个TestCase子类中每个以test开头的公共方法都是都被JUnit解析为一条TestCase,多条TestCase可以组成一个TestSuite,这里用到了Composite模式,这个后面再详细分析。JUnit4里也可以通过注解的方式(@Test)定义测试用例,这是后话。

package my.test;

import junit.framework.Assert;
import junit.framework.TestCase;

public class TestSimpleClass extends TestCase {

    public void testAdd() {
        int result = SimpleClass.add(1, 1);
        Assert.assertEquals(2, result);
    }
}

在上面的代码中,testAdd()方法会被解析成一个TestCase。也可以通过定义suite()方法来定义测试用例,两者差别不大。

准备好了被测代码和测试用例,就可以在Eclipse里设置断点、跟踪代码了。在Eclipse里launch debug的方法为,右键点击要debug的文件,debug as->debug configurations->Arguments,设置要测试的类,如图:

 

我是从junit.textui.TestRunner开始debug的。

JUnit结构

先看看JUnit的包结构:

 

JUnit的核心代码在junit.framework这个包中,junit.runner是运行测试用例时的相关代码,其中junit.runner.BaseTestRunner是一个抽象类。junit.awtui、junit.swingui、junit.textui是三种不同的运行JUnit的图形界面方式,每个包中都有一个TestRunner集成自junit.runner.BaseTestRunner。

我阅读的代码主要就是junit.framewokr、junit.textui这两个包,和junit.runner.BaseTestRunner。

下面是junit里几个重要的类的类图:

 

JUnit运行流程

JUnit的运行过程可以分为准备测试用例、执行用例并搜集测试结果两个阶段。以下代码中的getTest(testcase)是准备测试用例,doRun(suite, wait)执行用例:

 

try {
    if (!method.equals("")) 
        return runSingleMethod(testCase, method, wait);
    Test suite= getTest(testCase);
    return doRun(suite, wait);
} catch (Exception e) {
    throw new Exception("Could not create and run test suite: " + e);
}

 

下面是时序图:

 

JUnit用到的设计模式

Composite

JUnit在创建测试用例时,用到了composite模式。Junit.framework.Test是定义了测试用例的接口,其中包括run()和countTestCases()两个方法。TestCase和TestSuite是实现了Test接口的两个类,TestCase是单个测试用例,TestSuite是测试用例的集合。

Observer

JUnit在搜集测试结果是用到了observer模式。TestResult管理着一个TestListener的集合,当测试用例执行出现错误或者执行失败时,通知这些TestListener执行相应操作。下面是截取的一些代码:

管理TestListener的集合:

    /**
     * Registers a TestListener
     */
    public synchronized void addListener(TestListener listener) {
        fListeners.addElement(listener);
    }
    /**
     * Unregisters a TestListener
     */
    public synchronized void removeListener(TestListener listener) {
        fListeners.removeElement(listener);
    }

 

当测试用例执行失败时,通知TestListenner执行相关操作:

    public synchronized void addError(Test test, Throwable t) {
        fErrors.addElement(new TestFailure(test, t));
        for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
            ((TestListener)e.nextElement()).addError(test, t);
        }
    }

Template Method

Template模式比较简单,JUnit在BaseTestRunner.getTest()、TestCase.runBare()中都有用到。

posted on 2013-01-12 00:03  张孝军  阅读(970)  评论(0)    收藏  举报

导航