您的位置:首页 > 其它

一个通用的单元测试框架的思考和设计02-设计篇

2011-07-30 09:28 786 查看
第一节里介绍了我们框架设计的目标,这篇主要介绍的是这个框架主要的设计思路和关键技术点

1.如何扩展junit的功能,使junit在启动时可以做一些我们定制化的功能?

junit4建立了以Runner为核心的测试框架运行机制,在junit3的版本中,我们知道要运行一个junit测试用例,必须继承一个TestCase基类,junit4则不需要这个限制,只需要标注一下要运行测试的方法为@Test就可以了,怎么做到的呢?就是这个Runner机制,这里不介绍Junit4的运行机制,可以从org.junit.runner.BlockJUnit4ClassRunner中得到答案,像spring test框架也是扩展了这个类的功能来达到扩展目的的

2.如何让junit4框架提供更多的自定义注解的功能?

junit4提供了诸如@Test,@BeforeClass,@Before等注解来简化单元测试过程,在我们这个通用框架的设计中,我们系统提供更多自己定制的注解来扩展junit的功能,如我们希望提供一个@DataSet注解,当测试类有此注解时,框架自动解释这个注解,并把当前类同级目录下加载与类名相同的xsl文件,该文件里存放的是该单元测试类的准备数据,这样就能解决上一节中提到的测试文件和测试类之间约束的目的,开发只需要关注准备数据和写测试类,其他的事情都交给框架去搞吧,通过跟踪Junit的源码我们不难看出单元测试类的执行要经过Object
createTest()方法(测试框架加载测试类)和Statement methodInvoker(FrameworkMethod method, Object test)(执行测试方法),这样我们就可以通过扩展BlockJUnit4ClassRunner类通过覆写这两个方法,让其支持我们更多的功能特性

3.回顾一个测试用例的测试过程

一个测试用例的执行大约可以包含这样几个步骤,在创建测试实例后,测试方法前,测试方法执行后,测试方法抛出异常后,因此我们可以根据这些功能定义一个统一接口IUnitTestExecuteListener,接口里定义这4个方法

prepareTestInstance --创建测试实例后

beforeTest --测试方法前

afterTest -测试方法执行后

afterThrowable -测试方法抛出异常后

这样对于不同的功能扩展,我们只需要提供相应的子类即可,如我们前面提到的那个@DataSet注解的方式来加载测试数据准备文件,就可以提供一个ExcelDataProviderListener类,只要在其prepareTestInstance 方法里把测试文件内容读出来,插入到数据库中即可-so easy!,对于要进行事务控制的测试方法@Transactional标签,我们也可以提供一个实现类来实现事务控制的目的--这样对于框架而言,新功能的扩展只需要添加对应的子类即可,体现了软件设计的‘开-闭’原则

4.框架执行流程图

解释:IUnit是我们为这个通用框架YY的名字:)

从这张流程图上可以看出,IunitRunner和IUnitTestExecutionListener是我们整个框架的核心,一个Runner有多个Listener,当测试的生命周期开始后,runner会循环调用已注册listener的prepareTestInstance ,beforeTest ,afterTest ,afterThrowable 方法执行对应的功能



5.详细设计-类图

解释:整个框架最核心的类和接口只有三个IunitRunner,这个是运行的切入点,用来注册每个测试类指定的listener(通过寻找测试中上的@IUnitTestExecuteListeners标注),所有的功能扩展都是围绕IUnitTestExecuteListener展开,如类图中描述的GuiceStrapupListener用来启动guice容器,DataProviderListener用来加载测试准备数据



6.千呼万唤始出来-最终的测试用例长什么样子

对于最终使用框架的开发者而言,根据自身需要通过注解来动态加载所需要的listener即可(可以指定多个),注意测试用例上要加个@RunWith标注,指定要执行的runner为IunitRunner这样junit框架才能用我们提供的runner来运行,实际使用的时候这些东东可以都放到一个测试父类中去完成,开发者只需要关注自身用到的listener即可

package com.crazycoder2010.iunit;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;

import org.junit.Test;
import org.junit.runner.RunWith;

import com.crazycoder2010.iunit.annotation.IUnitDataSet;
import com.crazycoder2010.iunit.annotation.IUnitTestExecuteListeners;

@IUnitDataSet(dbunitFile="AppTest.xml")
@RunWith(IUnitRunner.class)
@IUnitTestExecuteListeners({TransactionalListener.class,DatasetProviderListener.class})
public class AppTest extends AbstractIUnitTestCase {
@Test
public void testHello(){
assertThat("hello", equalTo("hello"));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐