一个通用的单元测试框架的思考和设计01-思考篇
1.先从问题说起
写过程序的同学都知道,做好单元测试提高代码覆盖率对整个项目意味着什么,但是做好单元测试并不是一件那么简单的事情,因为实际业务逻辑和运行环境的复杂性,导致了我们的单元测试代码不可能都像那些helloWord那么简单,比如现在的业务系统绝大多数都是基于数据库的,怎么做单元测试才能做到每次做单元测试时都是一个干净的测试环境-即上次单元测试的数据库操作不会影响本次测试的结果(比如一个createUser操作,第一次单元测试运行成功了,但是第二次运行却失败了,因为代码里做了重名判断),还有web层的单元测试如何进行,web框架如何启动,那些万恶的httpServletRequest,HttpSession等接口,头大。。。
dbunit,基于数据库的测试框架,提供了可以通过xml格式来准备数据的方案,使测试数据和真实的数据库数据分离开,测试者可以针对自己在文件中造的数据进行程序的断言,也提供了一个与junit集成的基类DBTest,这个基类封装了一些dbunit启动的操作,把一些通用复杂的操作对操作者透明,但是这也是一个劣势,就是一旦继承了这个基类,你就无法继承自己的类(都是java单继承惹的祸)
SpringTest框架,spring2.5以后提供了一个test框架,提供了大量的基类,测试框架会自动启动spring容器,把spring中的bean自动注入进来,另外还提供了可以对测试方法进行事务控制,每个测试方法测试完成后通过框架控制自动回滚的功能,优势很明显,充分发挥了spring框架的优势,对开发者屏蔽细节,自动事务控制,缺点也很明显,测试必须依赖于spring框架,对于那些没用到spring框架的项目来说只能望洋兴叹了
Struts2Test,struts2提供的单元测试用例基类,提供对httprequest,response,session等对象mock(基于spring test 框架),可以初始化struts框架,这对基于struts2的应用系统来说是个福音,不幸的是要用这个框架,必须依赖spring框架,否则一切玩完
3.框架设计的目标
核心的框架都在上面了,不难看出,在这几个主流框架的使用中,spring框架在其中扮演了很重要的角色,如果项目中没有用到spring,有些测试框架的支持功能根本无法使用!如何让各个框架可以很容易的整合起来又能发挥自身最大的优势呢?
刚刚谈了理想,接下来看一下怎样的一个框架才能满足我们的需求
1)不需要和任何框架耦合在一起
这点很重要,整个框架应该围绕一个基本测试框架展看如testng或junit而不是spring这种重量级的框架(相对junit来说spring已经是很重量级的东东了)
2)可以很容易为框架添加新的特性,但是不需要改动框架本身的代码
--对于spring test或dbunit等框架,相对于我们的测试框架只是一些功能上的enhancement,可以通过功能扩展加到框架中,而不是通过继承他们提供基类的方式来直接依赖他们
3)准备测试数据
做基于db的单元测试的人都有感触,单元测试很大一部分时间都在准备数据,因此框架应该支持让使用者通过更加便利的方式去准备数据如常用的excel文件或xml文件或其他csv格式
框架使用者不需要去手动的加载这些数据准备文件,框架需要提供一种契约,如文件名和类名名称路径保持一致,框架自动为当前测试类加载对应的数据,框架使用者只需要书写测试代码,把测试数据放到指定文件夹下即可
4)事务控制
这个没什么捷径,只能靠jdbc的api来实现
写过程序的同学都知道,做好单元测试提高代码覆盖率对整个项目意味着什么,但是做好单元测试并不是一件那么简单的事情,因为实际业务逻辑和运行环境的复杂性,导致了我们的单元测试代码不可能都像那些helloWord那么简单,比如现在的业务系统绝大多数都是基于数据库的,怎么做单元测试才能做到每次做单元测试时都是一个干净的测试环境-即上次单元测试的数据库操作不会影响本次测试的结果(比如一个createUser操作,第一次单元测试运行成功了,但是第二次运行却失败了,因为代码里做了重名判断),还有web层的单元测试如何进行,web框架如何启动,那些万恶的httpServletRequest,HttpSession等接口,头大。。。
2.现有的框架及对比
目前有很多的开源测试框架,一下列举几个最常用的
junit这个地球人都知道,单元测试的先祖框架,核心,掌握他并熟练运用那是必须滴
testNG,号称下一代单元测试框架,火了一阵子,功能比junit更强大,但是依旧无法撼动junit的王者地位dbunit,基于数据库的测试框架,提供了可以通过xml格式来准备数据的方案,使测试数据和真实的数据库数据分离开,测试者可以针对自己在文件中造的数据进行程序的断言,也提供了一个与junit集成的基类DBTest,这个基类封装了一些dbunit启动的操作,把一些通用复杂的操作对操作者透明,但是这也是一个劣势,就是一旦继承了这个基类,你就无法继承自己的类(都是java单继承惹的祸)
SpringTest框架,spring2.5以后提供了一个test框架,提供了大量的基类,测试框架会自动启动spring容器,把spring中的bean自动注入进来,另外还提供了可以对测试方法进行事务控制,每个测试方法测试完成后通过框架控制自动回滚的功能,优势很明显,充分发挥了spring框架的优势,对开发者屏蔽细节,自动事务控制,缺点也很明显,测试必须依赖于spring框架,对于那些没用到spring框架的项目来说只能望洋兴叹了
Struts2Test,struts2提供的单元测试用例基类,提供对httprequest,response,session等对象mock(基于spring test 框架),可以初始化struts框架,这对基于struts2的应用系统来说是个福音,不幸的是要用这个框架,必须依赖spring框架,否则一切玩完
3.框架设计的目标
核心的框架都在上面了,不难看出,在这几个主流框架的使用中,spring框架在其中扮演了很重要的角色,如果项目中没有用到spring,有些测试框架的支持功能根本无法使用!如何让各个框架可以很容易的整合起来又能发挥自身最大的优势呢?
在进行具体的设计之前,我们来展望一下我们期望的测试流程是怎么样的(图)
刚刚谈了理想,接下来看一下怎样的一个框架才能满足我们的需求
1)不需要和任何框架耦合在一起
这点很重要,整个框架应该围绕一个基本测试框架展看如testng或junit而不是spring这种重量级的框架(相对junit来说spring已经是很重量级的东东了)
2)可以很容易为框架添加新的特性,但是不需要改动框架本身的代码
--对于spring test或dbunit等框架,相对于我们的测试框架只是一些功能上的enhancement,可以通过功能扩展加到框架中,而不是通过继承他们提供基类的方式来直接依赖他们
3)准备测试数据
做基于db的单元测试的人都有感触,单元测试很大一部分时间都在准备数据,因此框架应该支持让使用者通过更加便利的方式去准备数据如常用的excel文件或xml文件或其他csv格式
框架使用者不需要去手动的加载这些数据准备文件,框架需要提供一种契约,如文件名和类名名称路径保持一致,框架自动为当前测试类加载对应的数据,框架使用者只需要书写测试代码,把测试数据放到指定文件夹下即可
4)事务控制
这个没什么捷径,只能靠jdbc的api来实现