自訂 TestRunner


事實上,在 關於 TestCase 的後半段介紹中,已經有點自訂TestRunner的意味,所謂的TestRunner,無非就是呼叫Test介面實作物件上的run()方法,傳入TestResult實例收集測試的結果。

使用 TestSuite 最後的範例中,你也可以這麼作:
    ...
    public static Test suite() {
        TestSuite suite = new TestSuite();
        suite.addTest(new XXXTest("testABC"));  // 執行testABC()方法
        suite.addTest(YYYTest.suite());         // suite() 傳回 TestSuite實例
        suite.addTestSuite(OOOTest.class);      // 自動找出所有testXXX()方法
        return suite;
    }

    public static void main(String[] args) {
        TestResult result = new TestResult();
        suite().run(result);

        // 接著就看你取得TestResult如何呈現測試報告了

    }

觀察文字模式的TestRunner,其run()方法無非也只是代你作了這些事:
    static public TestResult run(Test test) {
        TestRunner runner= new TestRunner();
        return runner.doRun(test);
    }
   
    public TestResult doRun(Test test) {
        return doRun(test, false);
    }

    protected TestResult createTestResult() {
        return new TestResult();
    }
  
    public TestResult doRun(Test suite, boolean wait) {
        TestResult result= createTestResult();
        result.addListener(fPrinter);
        long startTime= System.currentTimeMillis();
        suite.run(result);
        long endTime= System.currentTimeMillis();
        long runTime= endTime-startTime;
        fPrinter.print(result, runTime);

        pause(wait);
        return result;
    }

上例中,資訊的收集,其實是由ResultPrinter負責(fPrinter參考的實例),其為TestListener的實作物件。

只不過,對於自訂TestRunner,JUnit提供了一個基礎類別BaseTestRunner,在這個類別中提供了一些讀取組態設定、指定名稱取得某個TestSuite實例的方便方法,讓你不用從頭開始撰寫這些方法。事實上,文字版本的TestRunner,就是繼承BaseTestRunner實作而來:
public class TestRunner extends BaseTestRunner {
    ...
}

觀察BaseTestRunner文字版的TestRunner之原始碼,你可以很快地學會自訂TestRunner,或者發現目前已有的TestRunner更多的使用方式。例如文字版的TestRunner,可以如下將測試結果存在檔案之中:

  • CalculatorTest.java
package cc.openhome;

import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.textui.TestRunner;
import java.io.*;

public class CalculatorTest extends TestCase {
private Calculator calculator;
public CalculatorTest() {}
public CalculatorTest(String name) {
super(name);
}

@Override
protected void setUp() {
calculator = new Calculator();
}

@Override
protected void tearDown() {
calculator = null;
}

public void testPlus() {
int expected = 5;
int result = calculator.plus(3, 2);
assertEquals(expected, result);
}

public void testMinus() {
int expected = 1;
int result = calculator.minus(3, 2);
assertEquals(expected, result);
}

public static void main(String[] args) throws IOException {
TestRunner runner = new TestRunner(
new PrintStream(
new FileOutputStream("calculator.test.log")));
runner.doRun(new TestSuite(CalculatorTest.class));
}
}