1 现有的单元测试框架
单元测试是保证程序正确性的一种有效的测试手段,对于不一样的开发语言,一般都能找到相应的单元框架。node
借助于这些单测框架的帮助,可以使得咱们编写单元测试用例的过程变得便捷而优雅。框架帮咱们提供了case的管理,执行,断言集,运行参数,全局事件工做,全部的这些使得咱们只需关注:于对于特定的输入,被测对象的返回是否正常。
那么,这些xUnit系列的单元测试框架是如何作到这些的了?分析这些框架,发现全部的单元测试框架都是基于如下的一种体系结构设计的。
web
如上图所示,单测框架中一般包括TestRunner, Test, TestResult, TestCase, TestSuite, TestFixture六个组件。
TestRuner:负责驱动单元测试用例的执行,汇报测试执行的结果,从而简化测试
TestFixture:以测试套件的形式提供setUp()和tearDown()方法,保证两个test case之间的执行是相互独立,互不影响的。
TestResult:这个组件用于收集每一个test case的执行结果
Test:做为TestSuite和TestCase的父类暴露run()方法为TestRunner调用
TestCase:暴露给用户的一个类,用户经过继承TestCase,编写本身的测试用例逻辑
TestSuite:提供suite功能管理testCase
正由于类似的体系结构,因此大多数单元测试框架都提供了相似的功能和使用方法。那么在单测中引入单元测试框架会带来什么好处,在现有单元测试框架下还会存在什么样不能解决的问题呢?
2 单元测试框架的优势与一些问题
在单元测试中引入单测框架使得编写单测用例时,不须要再关注于如何驱动case的执行,如何收集结果,如何管理case集,只须要关注于如何写好单个测试用例便可;同时,在一些测试框架中经过提供丰富的断言集,公用方法,以及运行参数使得编写单个testcase的过程获得了最大的简化。
那这其中会存在什么样的疑问了?
我在单元测试框架中写一个TestCase,与我单独写一个cpp文件在main()方法里写测试代码有什么本质却别吗?用了单元测试框架,并无解决我在对复杂系统作单测时遇到的问题。
没错,对于单个case这二者从本质上说是没有区别的。单元测试框架自己并无告诉你如何去写TestCase,在这一点上他是没有提供任何帮助的。因此对于一些复杂的场景,只用单元测试框架是有点多少显得无能为力的。
使用单元测试框架每每适用于如下场景的测试:单个函数,一个class,或者几个功能相关class的测试,对于纯函数测试,接口级别的测试尤为适用,如房贷计算器公式的测试。
可是,对于一些复杂场景:
被测对象依赖复杂,甚至没法简单new出这个对象
对于一些failure场景的测试
被测对象中涉及多线程合做
被测对象经过消息与外界交互的场景
…
单纯依赖单测框架是没法实现单元测试的,而从某种意义上来讲,这些场景反而是测试中的重点。
以分布式系统的测试为例,class 与 function级别的单元测试对整个系统的帮助不大,固然,这种单元测试对单个程序的质量有帮助;分布式系统测试的要点是测试进程间的交互:一个进程收到客户请求,该如何处理,而后转发给其余进程;收到响应以后,又修改并应答客户;同时分布式系统测试中一般更关注一些异常路径的测试,这些场景才是测试中的重点,也是难点所在。
Mock方法的引入一般能帮助咱们解决以上场景中遇到的难题。
3 Mock的引入带来了什么
在维基百科上这样描述Mock:In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways. A computer programmer typically creates a mock object to test the behavior of some other object, in much the same way that a car designer uses a crash test dummy to simulate the dynamic behavior. of a human in vehicle impacts.
Mock一般是指,在测试一个对象A时,咱们构造一些假的对象来模拟与A之间的交互,而这些Mock对象的行为是咱们事先设定且符合预期。经过这些Mock对象来测试A在正常逻辑,异常逻辑或压力状况下工做是否正常。
引入Mock最大的优点在于:Mock的行为固定,它确保当你访问该Mock的某个方法时老是可以得到一个没有任何逻辑的直接就返回的预期结果。
Mock Object的使用一般会带来如下一些好处:
隔绝其余模块出错引发本模块的测试错误。
隔绝其余模块的开发状态,只要定义好接口,不用管他们开发有没有完成。
一些速度较慢的操做,能够用Mock Object代替,快速返回。
对于分布式系统的测试,使用Mock Object会有另外两项很重要的收益:
经过Mock Object能够将一些分布式测试转化为本地的测试
将Mock用于压力测试,能够解决测试集群没法模拟线上集群大规模下的压力
4 Mock的应用场景
在使用Mock的过程当中,发现Mock是有一些通用性的,对于一些应用场景,是很是适合使用Mock的:
真实对象具备不可肯定的行为(产生不可预测的结果,如股票的行情)
真实对象很难被建立(好比具体的web容器)
真实对象的某些行为很难触发(好比网络错误)
真实状况令程序的运行速度很慢
真实对象有用户界面
测试须要询问真实对象它是如何被调用的(好比测试可能须要验证某个回调函数是否被调用了)
真实对象实际上并不存在(当须要和其余开发小组,或者新的硬件系统打交道的时候,这是一个广泛的问题)
固然,也有一些不得不Mock的场景:
一些比较难构造的Object:这类Object一般有不少依赖,在单元测试中构造出这样类一般花费的成本太大。
执行操做的时间较长Object:有一些Object的操做费时,而被测对象依赖于这一个操做的执行结果,例如大文件写操做,数据的更新等等,出于测试的需求,一般将这类操做进行Mock。
异常逻辑:一些异常的逻辑每每在正常测试中是很难触发的,经过Mock能够人为的控制触发异常逻辑。
在一些压力测试的场景下,也不得不使用Mock,例如在分布式系统测试中,一般须要测试一些单点(如namenode,jobtracker)在压力场景下的工做是否正常。而一般测试集群在正常逻辑下没法提供足够的压力(主要缘由是受限于机器数量),这时候就须要应用Mock去知足。
在这些场景下,咱们应该如何去作Mock的工做了,一些现有的Mock工具能够帮助咱们进行Mock工做。
网络