事實上,在 關於 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));
    }
}

