From Gossip@caterpillar

JUnit Gossip: TimedTest

在這邊以實際的例子,來看看如何撰寫TimedTest,首先假設您撰寫了一個字串工具類別,當中有個方法是串接字串,從字串"1"串接至"1000"。
  • StringTools.java
package onlyfun.caterpillar;

public class StringTools {
public static String oneToThousand() {
String str = "";
for(int i = 1; i < 1000; i++) {
str = str + i + "+";
}
str = str + "1000";

return str;
}
}

您首先會為這個字串工具類別撰寫一個單元測試,看看測試結果運行是否正確:
  • StringToolsTest.java
package onlyfun.caterpillar.test;

import onlyfun.caterpillar.StringTools;
import junit.framework.TestCase;

public class StringToolsTest extends TestCase {
public StringToolsTest() {}

public StringToolsTest(String name) {
super(name);
}

public void testOneToTen() {
String result = StringTools.oneToThousand();
assertTrue(result.endsWith("1000"));
}

public static void main(String[] args) {
junit.textui.TestRunner.run(StringToolsTest.class);
}
}

在執行結果正確的情況下:
.
Time: 0.016

OK (1 test)


我們進一步期待它運行的效率,必須在0.01秒內完成,我們可以使用JUnitPerf的TimedTest來撰寫測試:
  • ExampleTimedTest.java
package onlyfun.caterpillar.test;

import com.clarkware.junitperf.TimedTest;

import junit.framework.Test;
import junit.framework.TestSuite;

public class ExampleTimedTest {
public static Test suite() {
long maxElapsedTime = 10;
Test testCase = new StringToolsTest("testOneToThousand");
Test timedTest = new TimedTest(testCase, maxElapsedTime);
return timedTest;

}

public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
}

您所要作的,就是將JUnit的TestCase設定給TimedTest,您也可以使用TestSuite:
    public static Test suite() {
        long maxElapsedTime = 10;
       
        TestSuite suite = new TestSuite(StringToolsTest.class);
        Test timedTest = new TimedTest(suite, maxElapsedTime);
       
        return timedTest;
       
    }

初步運行時,程式的JUnit結果是測試成功,但效能測試超出時間預期:

.TimedTest (WAITING): testOneToThousand(onlyfun.caterpillar.test.StringToolsTest): 16 ms
F
Time: 0.016
There was 1 failure:
1) testOneToThousand(onlyfun.caterpillar.test.StringToolsTest)junit.framework.AssertionFailedError: Maximum elapsed time exceeded! Expected 10ms, but was 16ms.
    at com.clarkware.junitperf.TimedTest.runUntilTestCompletion(TimedTest.java:161)
    at com.clarkware.junitperf.TimedTest.run(TimedTest.java:138)
    at onlyfun.caterpillar.test.ExampleTimedTest.main(ExampleTimedTest.java:23)

FAILURES!!!
Tests run: 1,  Failures: 1,  Errors: 0


字串串接不應當用'+',這會產生許多不必要的物件,您要用StringBuilder或StringBuffer,例如將StringTools改為:
  • StringTools.java
package onlyfun.caterpillar;

public class StringTools {
public static String oneToThousand() {
StringBuffer str = new StringBuffer("");
for(int i = 1; i < 1000; i++) {
str.append(i);
str.append("+");
}
str.append("1000");
 
return str.toString();
}
}

再次運行ExampleTimedTest,這次就可以通過測試了:
.TimedTest (WAITING): testOneToThousand(onlyfun.caterpillar.test.StringToolsTest): 0 ms

Time: 0

OK (1 test)


要注意的是,JUnitPerf所量測的時間,是包括了JUnit的TestCase之setUp()、testXXX()與tearDown()方法, 如果想準確量測某個單元,先行準備好測試的相關設備,透過建構子設定給測試案例,暫時略過setUp()、tearDown()等方法之執行是一個方式。