关闭

有效应用的设计模式与灵活的单元测试途径

发表于:2008-7-30 15:41

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:熊伟    来源:IBM

  引言

  设计模式是对被用来在特定场景下解决一般设计问题的类和相互通信的对象的描述,通过在系统设计中引入合适的设计模式可以为系统实现提供更大的灵活性,从而有效地控制变化,更好地应对需求变更或者按需变更系统运行路径等问题。

  单元测试是软件开发的一个重要组成部分,是与编码实现同步进行的开发活动,这一点已成为软件开发者的共识。适度的单元测试不但不会影响开发进度,反而可以为开发过程提供很好的控制,为软件质量、系统重构等提供有力的保障,并且,当后续系统需求发生变更、Bug Fix 或功能扩展时,能很好地保证已有实现不会遭到破坏,从而使得程序更易于维护和修改。 Martin Fowler、Kent Beck、Robert Martin 等软件设计领域泰斗更是极力倡导测试先行的测试驱动开发(Test Driven Development,TDD)的开发方式。

  单元测试主要用于测试细粒度的程序单元,如类的某个复杂方法的正确性,也可以根据需要综合测试某个操作所涉及的多个相互联系的类的正确性。在很多情况下,相互联系的多个类中有些类比较简单,为这些简单类单独编写单元测试用例往往不如将它们与使用它们的类一起进行测试有意义。

  模拟对象(Mock Objects)是为模拟被测试单元所使用的外围对象、设备(后文统一简称为外部对象)而设计的一种特殊对象,它们具有与外部对象相同的接口,但实现往往比较简单,可以根据测试的场景进行定制。由于单元测试不是系统测试,方便、快速地被执行是单元测试的一个基本要求,直接使用外部对象往往需要经过复杂的系统配置,并且容易出现与欲测试功能无关的问题;对于一些异常的场景,直接使用外部对象可能难以构造,而通过设计合适的 Mock Objects,则可以方便地模拟需要的场景,从而为单元测试的顺利执行提供有效的支持。

  本文根据笔者经验,介绍了几种典型的设计模式在系统设计中的应用,及由此为编写单元测试带来的方便。

  从对象创建开始

  由于需要使用 Mock Objects 来模拟外部对象的功能,因此必须修改正常的程序流程,使得被测试功能模块与 Mock Objects,而不是外部对象进行交互。要做到这一点,首先要解决的问题就是对象创建,即在原本创建外部对象的地方创建 Mock Objects,因此在设计、实现业务逻辑时需要注意从业务逻辑中分离出对象创建逻辑。

  actory Method 是一种被普遍运用的创建型模式,用于将对象创建的职责分离到独立的方法中,并通过子类化来实现创建不同对象的目的。如果被测试单元所使用的外部对象是通过 Factory Method 创建的,则可以通过从已有被测试的 Factory 类派生出一个新的 MockFactory,以创建 Mock Objects,并在 setUp 测试中创建 MockFactory,从而间接达到对被测试类进行测试的目的。

  下面的代码片段展示了具体的做法:

// BaseObjects.java
package com.factorymethod.demo;
public interface BaseObjects {
voidfunc();
}

// OuterObjects.java
package com.factorymethod.demo;
public class OuterObjects implements BaseObjects {
public void func() {
System.out.println("OuterObjects.func");
}
}

// LogicToBeTested.java, code to be tested
package com.factorymethod.demo;
public class LogicToBeTested {
public void doSomething() {
BaseObjects b = createBase();
b.func();
}

public BaseObjects createBase() {
return newOuterObjects();
}
}

  以下则是对应的 MockOuterObjects、MockFactory 以及单元测试的实现:

// MockOuterObjects.java
package com.factorymethod.demo;
public class MockOuterObjects implements BaseObjects {
public void func() {
System.out.println("MockOuterObjects.func");
}
}

// MockLogicToBeTested.java
package com.factorymethod.demo;
public class MockLogicToBeTested extends LogicToBeTested {
public BaseObjects createBase() {
return new MockOutterObjects();
}
}

// LogicTest.java
package com.factorymethod.demo;
import junit.framework.TestCase;

public class LogicTest extends TestCase {
LogicToBeTested c;
protected void setUp() {
c =new MockLogicToBeTested();
}
public void testDoSomething() {
c.doSomething();
}
}

41/41234>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号