当 JUnit 不必区分其运行的是一个或多个测试用例时,能够轻松地解决这个问题的模式就
是 Composite(组合)模式。摘引其意图,"将对象组合成树形结构以表示'部分-整体'的层次
结构。Composite 使得用户对单个对象和组合对象的使用具有一致性。"在这里'部分-整体'
的层次结构是解决问题的关键,可以把单个的 TestCase 看作部分,而把复合的 TestCase 看
作整体(称为 TestSuit) 。这样使用该模式便可以恰到好处得解决了这个难题。
Composite 模式引入以下的参与者:
Component:这是一个抽象角色,它给参加组合的对象规定一个接口。这个角色,
给出共有的接口和默认行为。其实就我们的 Test 接口,它定义出 run 方法。
Composite:实现共有接口并维护一个测试用例的集合。就是复合测试用例 TestSuit
Leaf:代表参加组合的对象,它没有下级子对象,仅定义出参加组合的原始对象的
行为,其实就是单一的测试用例 TestCase,它仅实现 Test 接口的方法。
其实 componsite 模式根据所实现的接口类型区分为两种形式,分别称为安全式和透明式。
JUnit 中使用了安全式的结构,这样在 TestCase 中没有管理子对象的方法。
composite 模式告诉我们要引入一个 Component 抽象类,为 Leaf 对象和 composite 对象
定义公共的接口。这个类的基本意图就是定义一个接口。在 Java 中使用 Composite模式时,
优先考虑使用接口,而非抽象类,因此引入一个 Test 接口。当然我们的 leaf 就是 TestCase
了。其源代码如下:
//composite模式中的Component角色
public interface Test {
public abstract void run(TestResult result);
}
//composite模式中的Leaf角色
public abstract class TestCase extends Assert implements Test {
public void run(TestResult result) {
result.run(this);
}
}
下面,列出 Composite 源码。将其取名为 TestSuit 类。TestSuit 有一个属性 fTests (Vector
类型)中保存了其子测试用例,提供 addTest 方法来实现增加子对象 TestCase ,并且还提供
estCount 和 tests 等方法来操作子对象。最后通过 run()方法实现对其子对象进行委托
(delegate) ,最后还提供 addTestSuite 方法实现递归,构造成树形。
public class TestSuite implements Test {
private Vector fTests= new Vector(10);
public void addTest(Test test) {
fTests.addElement(test);
}
public Enumeration tests() {
return fTests.elements();
}
public void run(TestResult result) {
for (Enumeration e= tests(); e.hasMoreElements(); ) {
Test test= (Test)e.nextElement();
runTest(test, result);
}
}
public void addTestSuite(Class testClass) {
addTest(new TestSuite(testClass));
}
}
注意所有上面的代码是对 Test 接口进行实现的。 由于 TestCase 和 TestSuit两者都符合 Test
接口,我们可以通过 addTestSuite 递归地将 TestSuite 再组合成 TestSuite,这样将构成树形结
构。所有开发者都能够创建他们自己的 TestSuit。测试人员可创建一个组合了这些测试用例
的 TestSuit 来运行它们所有的 TestCase。
public static Test suite() {
TestSuite suite1 = new TestSuite("我的测试TestSuit1");
TestSuite suite2 = new TestSuite("我的测试TestSuit2");
suite1.addTestSuite(untitled6.Testmath.class);
suite2.addTestSuite(untitled6.Testmulti.class);
suite1.addTest(suite2);
return suite1;
}