`
jiangduxi
  • 浏览: 456382 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Test an object that instantiates other objects

阅读更多
问题:
  你想测试一个对象,但这个对象内部还初始化其他对象,这使得测试变得困难

背景:
   面向对象的设计是双刃剑。我们使用聚合来表明一个对象拥有另外一个对象,比如大多数情况下一个汽车都有自己的轮子。而另一方面,为了单独测试一个对象,我们需要将对象像拼图游戏一样拼凑起来。这就是说,测试更期望对象使用组合而不是聚合。如果你要测试的对象初始化了其他的对象,那么只有在保证内部对象的正确性的前提下,你才能测试这个对象,而这就违反了单独测试一个对象的原则。

  我们不安地发现,仍然有大量的程序员对进行测试的好处一无所知。这致使他们过多地使用聚合。他们的设计中充满了初始化其他对象的对象,或者常常从全局的位置获取对象。这种编程办法,如果不改进的话,就会造成强耦合的架构,导致测试难以进行。我们知道:我们继承了大量这种设计,甚至直接创建了它们。下面的诀窍介绍了一个基本的测试技巧,它可以带来程序设计上的一些提高,是单独的测试一个对象成为可能。

诀窍:
  为了处理这个问题,你要将要测试的对象的内部对象用其他的对象代替。这就有两个问题需要解决:
1. 如何创建这个对象所包含的对象的替身
2. 如果将它传递给要测试的对象

为了简化讨论,我们使用术语“测试对象”(不要与对象测试相混淆),用来指代那些你要测试的类或者接口的实例。有多种不同的测试对象:假的、残缺的、模拟的。

  创建一个接口的测试对象很简单:只要创建一个类,并用最简单的方法实现这个接口就可以了,这是最简单的测试对象。在这里我们使用EasyMock(www.easymock.org)来创建接口的测试对象。之所以使用这个包,是因为它不仅可以避免我们重复的劳动,还能保证我们仿造的接口对象的一致性和统一性。这让我们的测试程序更容易理解。

创建一个类的测试对象,可以创建它的一个子类,然后仿造它的全部方法,或者干脆屏蔽它的全部方法。一个仿造的方法返回某种可预见的、有意义的、硬编码的值,而一个屏蔽的方法不做任何有意义的事情,只需要实现编译要求即可。你也许会发现:在要测试的对象中声明接口,然后在测试时转变为具体类的对象是很有好处的。因为这样你就可以使用前面介绍的EasyMock了。此外,如果你在对象中要使用其他的对象,最好将其声明为接口,这样你的设计就更有弹性。

  至于第二个问题,我们有两种方法可以让你将一个测试对象传递给另一个要测试的对象:一种是改造构造函数,另一种是添加一个set方法。我们认为改造构造函数的方法比较简单,这样可以避免在测试中再去调用set方法。为了说明,可以看个例子
  public class Deployment{
     public void deploy(File targetFile
 throws FileNotFoundException{
 Deployer.getInstance().deploy(this, targetFile);
 }
}

注意,Deployment使用类级别的方法Deployer.getInstance()来生成Deployer。如果你想仿造一个Deployer,你需要将一个Deployer通过某种方法传递给Deployment。我们推荐使用构造函数来传递,所有新加一个构造函数并创建一个实例来保存Deployer;
 public class Depliyment{
    private Deployer deployer;

   public Deployment(Deployer deployer){
    this.deployer  = deployer;
   }

  public void deploy(File targetFile)throws FileNotFoundException{
      deployer.deploy(this, targetFile);
  }
 
   }

怎么好像没看见Deployer.getInstance()方法?我们不能丢掉这段代码:现在我们删除了无参数的构造函数,那么我们需要添加一个新的构造函数。
  public class Deployment{
    
     private Deployer deployer;
    public Deployment(){
     this(Deployer.getInstance());
    }
public Deployment(Deployer deployer){
    this.deployer  = deployer;
   }
public void deploy(File targetFile){
   deployer.deploy(this, targetFile);
}

  }

现在,当产品代码使用无参构造函数创建一个Deployment时,就可以观察到期望的行为:Deployment将使用Singleton Deployer。不过,在我们的测试中,我们使用一个假的Deployer,这样做可以模拟诸如目标文件不存在等情况。下面的代码是一个“故障测试”的Deployer------它永远都认为目标文件不存在
  public class FileNotFoundDeployer extends Deployer{
    public void deploy(Deployment deployment, File targetFile)throws FileNotFundException{
    throw new FileNotFoundException(targetFile.getPath());
 }
  }

现在,我们可以测试当Deployer部署失败的时候,Deployment如何表现。
  public void testTargetFileNotFound() throws Exception{
    Deployer fileNotFoundDeployer = new FileNotFoundDeployer();
   Deployment deployment = new Deployment(fileNotFoundDeployer);

  try{
       deployment.deploy(new File("hello"));
       fail("Found target file?!");
     }
catch(FileNotFoundException expected){
  assertEquals("hello", expected.getMessage());
}
}

这个测试演示了如何替换一个对象中引用的测试对象,同时也介绍了如何通过继承仿制测试对象。我们将使用的对象变成了构造函数的一个可选参数:如果我们没有提供的话,那么类也会自动察觉,并创建一个默认的。
分享到:
评论

相关推荐

    Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development (3rd Edition)

    3 edition (October 30, 2004) <br>Applying UML and Patterns is the world\'s #1 business and college introduction to \"thinking in objects\"and using that insight in real-world object-oriented ...

    Object Oriented Programming with Swift 2

    This is a very useful resource for developers who want to shift from Objective C, C#, Java, Python, JavaScript, or other object-oriented languages to Swift What You Will Learn Build solid, stable, ...

    Javascript.Object.Oriented.Programming.pdf

    Capture objects from real-world elements and create object-oriented code that represents them Learn the latest ES6 features and how to test and debug issues with JavaScript code using various modern ...

    Prentice.Hall.PTR.Rapid.J2EE.Development.An.Adaptive.Foundation.for.Enterprise.Applications.chm

    relational mapping Practical test-driven development: constructing automated unit test suites and using mock objects to \"test from the inside out\" Leveraging the full value of Eclipse and other IDEs...

    squish test

    This method aims to provide a standard and predictable set of tests that can be used to check software before it is uploaded to an FTP site. Let’s delve into the details of this automated testing ...

    A 3D Modeller-Erick Dransch.zip

    would have features that check whether the object is actually valid to print, an electrical CAD tool would simulate the physics of electricity running through copper, and a film special effects suite...

    Intermediate Perl.pdf

    Add behavior to an object that is going away, including object persistence. Chapter 14, Some Advanced Object Topics Use multiple inheritance, automatic methods, and references to filehandles. ...

    Programming in C++ for Engineering and Science

    To make it easier for novices to develop programs, the author uses an object-centered design approach that helps students identify the objects in a problem and the operations needed; develop an ...

    Google C++ Style Guide(Google C++编程规范)高清PDF

    The definition of an inline function needs to be in a header file, so that the compiler has the definition available for inlining at the call sites. However, implementation code properly belongs in ....

    api_object.zip_API_java_lipsziy

    return Objects.equals(name, other.name) && age == other.age; } ``` 在测试类 `Test_equals.java` 中,会创建多个 `Person` 对象,并使用 `equals()` 方法进行比较,以验证是否能正确判断对象的相等性。 总之...

    D3D render pipeline

    of 2D images, an object to assist in rendering to a surface or an environment map and objects for the rendering of special e®ects. Chapter 19 describes the mesh objects provided by D3DX. The mesh ...

    IOS5 Programming Cookbook

    It allows you to test your app without needing an actual device. - **Choosing Devices**: The simulator supports multiple device types (e.g., iPhone, iPad) and versions of iOS. Choosing the right ...

    Learning Underscore.js

    Explore the Underscore.js library by example using a test-driven development approach About This Book Understand and learn to apply functional programming principles using the built-in functions of ...

    python3.6.5参考手册 chm

    PEP 372: Adding an Ordered Dictionary to collections PEP 378: Format Specifier for Thousands Separator PEP 389: The argparse Module for Parsing Command Lines PEP 391: Dictionary-Based Configuration...

    PLSQL.Developer v11.0.0.1762 主程序+ v10中文包+keygen

    For each connection you can now define an initialization script that will be executed for each database session that is created for the connection Test Manager enhancements Notes tab page added ...

    Learning Python

    Then, the authors address the mechanics of the language itself, providing illustrations of how Python conceives of numbers, strings, and other objects as well as the operators you use to work with ...

    PLSQL.Developer(X32) v12.0.1.1814主程序+ v11中文包+keygen

    When viewing or editing LOB's the contents for common data formats will automatically be recognized, so that an external viewer or editor can be invoked: Changes made and saved in an external editor ...

Global site tag (gtag.js) - Google Analytics