簡 單的測試每個人都會寫。例如,現在測試人員撰寫測試案例,你負責提供測試案例的執行器(Test runner),讓測試人員可以執行測試案例以觀看測試結果。
如果測試人員看到某個類別:
package
cc.openhome;
public class Calculator {
public int plus(int op1, int op2) {
...
}
}
public class Calculator {
public int plus(int op1, int op2) {
...
}
}
測試人員撰寫了以下的測試:
package
test.cc.openhome;
import cc.openhome.Calculator;
public class CalculatorTest {
public static void testPlus() {
Calculator calculator = new Calculator();
int expected = 3;
int result = calculator.plus(1, 2);
if(expected == result) {
System.out.println("成功!");
}
else {
System.out.printf(
"失敗,預期為 %d,但是傳回 %d!%n", expected, result);
}
}
}
import cc.openhome.Calculator;
public class CalculatorTest {
public static void testPlus() {
Calculator calculator = new Calculator();
int expected = 3;
int result = calculator.plus(1, 2);
if(expected == result) {
System.out.println("成功!");
}
else {
System.out.printf(
"失敗,預期為 %d,但是傳回 %d!%n", expected, result);
}
}
}
為了讓測試人員可以執行測試,你撰寫了TestRunner給測試人員作為執行器:
package
test.cc.openhome;
public class TestRunner {
public static void main(String[] args) {
CalculatorTest.testPlus();
}
}
public class TestRunner {
public static void main(String[] args) {
CalculatorTest.testPlus();
}
}
接著,開發人員在 Calculator類別中新增了方法:
package
cc.openhome;
public class Calculator {
...
public int minus(int op1, int op2) {
...
}
}
public class Calculator {
...
public int minus(int op1, int op2) {
...
}
}
於是測試人員又在CalculatorTest中 撰寫了另一個測試:
package
test.cc.openhome;
import cc.openhome.Calculator;
public class CalculatorTest {
...
public static void testMinus() {
Calculator calculator = new Calculator();
int expected = 1;
int result = calculator.minus(3, 2);
if(expected == result) {
System.out.println("正確!");
}
else {
System.out.printf(
"錯誤,傳回 %d,但應該是 %d!%n", result, expected);
}
}
}
import cc.openhome.Calculator;
public class CalculatorTest {
...
public static void testMinus() {
Calculator calculator = new Calculator();
int expected = 1;
int result = calculator.minus(3, 2);
if(expected == result) {
System.out.println("正確!");
}
else {
System.out.printf(
"錯誤,傳回 %d,但應該是 %d!%n", result, expected);
}
}
}
為了可以執行新的測試案例,你為測試人員修改了TestRunner:
package
test.cc.openhome;
public class TestRunner {
public static void main(String[] args) {
CalculatorTest.testPlus();
CalculatorTest.testMinus();
}
}
public class TestRunner {
public static void main(String[] args) {
CalculatorTest.testPlus();
CalculatorTest.testMinus();
}
}
接著測試人員執行測試,卻發現了結果報告中出現了「成功!」與「正確!」。你檢視測試人員撰寫的程式,發現當中testPlus()與 testMinus()的程式流程類似,但報告訊息格式不一致。身為程式設 計師,馬上就想到重構(Refactor)一下,重複的部份可以提取出來:
package
test.cc.openhome;
public class Assert {
public static void assertEquals(int expected, int result) {
if(expected == result) {
System.out.println("正確!");
}
else {
System.out.printf(
"失敗,預期為 %d,但是傳回 %d!%n", expected, result);
}
}
}
public class Assert {
public static void assertEquals(int expected, int result) {
if(expected == result) {
System.out.println("正確!");
}
else {
System.out.printf(
"失敗,預期為 %d,但是傳回 %d!%n", expected, result);
}
}
}
你告訴測試人 員,除了TestRunner之外,現在要斷言可以使用Assert上的工具方法。現在測試人員將CalculatorTest修改如下:
package
test.cc.openhome;
import cc.openhome.Calculator;
public class CalculatorTest {
public static void testPlus() {
Calculator calculator = new Calculator();
int expected = 3;
int result = calculator.plus(1, 2);
Assert.assertEquals(expected, result);
}
public static void testMinus() {
Calculator calculator = new Calculator();
int expected = 1;
int result = calculator.minus(3, 2);
Assert.assertEquals(expected, result);
}
}
import cc.openhome.Calculator;
public class CalculatorTest {
public static void testPlus() {
Calculator calculator = new Calculator();
int expected = 3;
int result = calculator.plus(1, 2);
Assert.assertEquals(expected, result);
}
public static void testMinus() {
Calculator calculator = new Calculator();
int expected = 1;
int result = calculator.minus(3, 2);
Assert.assertEquals(expected, result);
}
}
開發人員不斷地在Calculator中加入新的xxx ()方法,而測試人員不斷地在CalculatorTest增加testXxx()方法,而你得在TestRunner中加入新的 CalculatorT.testXXX()方法。
你覺得很煩,雖然撰寫TestRunner是 你的職責,但是不想陪測試人員耗下去,因為測試請求是無窮無盡地,絕對沒 道理測試人員想增加一個測試,你就得修改一次TestRunner。於 是你設計了一個介面:
package test.cc.openhome;
public interface Test {
void run();
}
public interface Test {
void run();
}
然後將TestRunner修 改如下:
package
test.cc.openhome;
import java.util.*;
public class TestRunner {
private List<Test> tests;
public TestRunner() {
tests = new ArrayList<Test>();
}
public void add(Test test) {
tests.add(test);
}
public void run() {
for(Test test : tests) {
test.run();
}
}
}
import java.util.*;
public class TestRunner {
private List<Test> tests;
public TestRunner() {
tests = new ArrayList<Test>();
}
public void add(Test test) {
tests.add(test);
}
public void run() {
for(Test test : tests) {
test.run();
}
}
}
你想下班了,你告訴測試人員,現在測試案例要實作Test介面。例如:
package
test.cc.openhome;
import cc.openhome.Calculator;
public class CalculatorPlusTest implements Test {
@Override
public void run() {
Calculator calculator = new Calculator();
int expected = 3;
int result = calculator.plus(1, 2);
Assert.assertEquals(expected, result);
}
}
import cc.openhome.Calculator;
public class CalculatorPlusTest implements Test {
@Override
public void run() {
Calculator calculator = new Calculator();
int expected = 3;
int result = calculator.plus(1, 2);
Assert.assertEquals(expected, result);
}
}
package
test.cc.openhome;
import cc.openhome.Calculator;
public class CalculatorMinusTest implements Test {
@Override
public void run() {
Calculator calculator = new Calculator();
int expected = 1;
int result = calculator.minus(3, 2);
Assert.assertEquals(expected, result);
}
}
import cc.openhome.Calculator;
public class CalculatorMinusTest implements Test {
@Override
public void run() {
Calculator calculator = new Calculator();
int expected = 1;
int result = calculator.minus(3, 2);
Assert.assertEquals(expected, result);
}
}
新的TestRunner也 給測試人員了,這個TestRunner可 以讓測試人員自由增加測試案例,然後執行測試:
package
test.cc.openhome;
public class CalculatorTest {
public static void main(String[] args) {
TestRunner runner = new TestRunner();
runner.add(new CalculatorPlusTest());
runner.add(new CalculatorMinusTest());
runner.run();
}
}
public class CalculatorTest {
public static void main(String[] args) {
TestRunner runner = new TestRunner();
runner.add(new CalculatorPlusTest());
runner.add(new CalculatorMinusTest());
runner.run();
}
}
畢竟,測試案例如何撰寫與添加是由測試人員掌握,應該要有一個執行器,可以單純地接受測試案例並執行。
現在測試人員與開發人員繼續留下來繼續寫他的測試案例,不過你的TestRunner目前不用再修改 了,所以可以下班回家逍遙了。
這其實就是 Command 模式 的實現。
故事往往不會這麼就結束...XD