Test Double介绍:Dummy、Fake、Stub、Spy、Mock

Test Double

我们时常会遇到由于待测系统依赖组件无法工作而造成的测试阻碍,这是严重影响项目交付的风险之一,而Test Double就是规避这个风险的手段。Gerard Meszaros 在xUnit Patterns中提出 Test Double

Test Double只是一个通用的词,代表为了达到测试目的并且减少被测试对象的依赖,使用double(替身/复制品)代替一个真实的依赖对象,允许我们独立而解耦地测试某个模块,不再担心受到系统中其他部分的影响,从而保证了测试的速度和稳定性

在测试过程中,Test Double替代真实的依赖组件去和待测系统进行交互,Test Double不必和真实的依赖组件的实现一模一样,比如不用去实现依赖组件复杂的内部逻辑等,只需要在满足测试需求范围内,确保对于待测系统来说Test Double提供的API是和依赖组件提供的一样的,API是怎么实现的在这个上下文就显得不重要了。基于这个特点,Test Double多用于自动化测试比如单元测试和集成测试

Test Double类型

Dummy、Fake、Stub、Spy、Mock

摘自Martin Fowler Test Double:

  • Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.
  • Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an InMemoryTestDatabase eg. H2 Database is a good example).
  • Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test.
  • Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.
  • Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don't expect and are checked during verification to ensure they got all the calls they were expecting.

个人理解:

  • Dummy:为了成功调用被测方法而传入的假参数对象
  • Fake:指一个轻量级的完全代替待测系统依赖组件的对象,采用更加简单的方法实现依赖组件的功能。可以是一个“fake DB”比如简单的内存数据库来代替真实的重量级的数据库,也可以是一个“fake web service”比如创建一个简单的web service来返回指定的response
  • Stub:一个完全代替待测系统依赖组件的对象,这个对象按照我们设计的输出与待测系统进行交互,可以理解是在待测系统内部打的一个桩。这个桩既不会与测试用例(代码)交互,也不会在待测系统内部进行验证。Test Stub常用于响应待测系统的请求,然后返回特定的值
  • Spy:指一个待测系统依赖组件的替身,并且会捕捉和保存待测对象对依赖系统的输出,这个输出会用于测试代码中的验证。Test Spy主要用于记录和验证待测对象对依赖系统的输出
  • Mock:指一个完全代替待测系统依赖组件,并且用于验证待测系统输出的对象。这个对象接受待测系统的输出,进行处理并对这个输出进行验证,一旦验证通过也会返回值给待测系统。Mock Object主要用于接收待测系统的输出,然后进行验证

mock fake stub 区别

摘自whats the difference between faking mocking and stubbing

  • Fake: a class that implements an interface but contains fixed data and no logic. Simply returns "good" or "bad" data depending on the implementation.
  • Mock: a class that implements an interface and allows the ability to dynamically set the values to return/exceptions to throw from particular methods and provides the ability to check if particular methods have been called/not called.
  • Stub: Like a mock class, except that it doesn't provide the ability to verify that methods have been called/not called.

Fake Object和Test Stub很类似,都是依赖组件的代替,区别就在于Fake Object这个“轻量级”的定义。“轻量级”是指Fake Object仅仅提供和依赖组件一样的功能接口保证待测系统正常工作,让待测系统认为Fake Object就是“真的”依赖组件,实现细节可以非常简单,不需要具有真实依赖组件的很多特性,也不需要像Test Stub那样接受测试的需求,返回特定response给待测系统

Mock Object一个重要的特点是它可以对无法在待测系统上直接被观察到的行为或输出进行验证。无法观察到的系统行为或输出可以是数据插入数据库,可以是数据写入文件,也可以是对其他组件的调用。以数据库类型Mock Object举例,这个Mock的数据库会去接受待测系统发过来的数据,并且对这个数据进行验证,一旦验证通过就会对数据进行处理(插入或更新操作),然后测试代码会去验证插入是否成功

Fake Object的实现比Test Stub和Mock Object简单,所以更加可以快速满足测试需求。不过如果需要控制依赖组件对待测系统的输入或输出,应该使用Test Stub和Mock Object

Python中的Test Double模块

  • doublex - Powerful test doubles framework for Python
  • mock - Python standard library. A mocking and patching library
  • httpretty - HTTP request mock tool for Python.

参考及扩展阅读