博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个通用的单元测试框架的思考和设计03-实现篇-核心类源码
阅读量:6951 次
发布时间:2019-06-27

本文共 5715 字,大约阅读时间需要 19 分钟。

第二节里我们介绍了iunit整体的设计思路以及核心类之间的关系,这篇将以源码+解释的方式来演示核心类的实现方式

1.IUnitRunner 类

这个类是测试的入口类,直接继承自junit4.8的BlockJunit4ClassRunner,在构造函数里,我们把iunit框架的扩展功能添加了进来,因为整个框架呃设计都是基于Listener的,所以只需要把监听器在框架运行的时候加载进来即可--见构造函数,listener的注册是通过注解来进行的,因为测试类本身可能会有继承关系,因此需要遍历父类中的Listener,把子类+所有父类中的Listener合并起来,当然还要注意剔除掉重复注册的Listener,否则很可能导致一个Listener被执行多次(既在子类中注册过了又在父类中注册过了)

package com.crazycoder2010.iunit;import java.util.ArrayList;import java.util.List;import org.junit.Ignore;import org.junit.internal.AssumptionViolatedException;import org.junit.internal.runners.model.EachTestNotifier;import org.junit.runner.Description;import org.junit.runner.notification.RunNotifier;import org.junit.runners.BlockJUnit4ClassRunner;import org.junit.runners.model.FrameworkMethod;import org.junit.runners.model.InitializationError;import org.junit.runners.model.Statement;import com.crazycoder2010.iunit.annotation.IUnitTestExecuteListeners;public class IUnitRunner extends BlockJUnit4ClassRunner {	/**	 * 监听器	 */	private List
executeListeners = new ArrayList
(); private Class
clazz; private TestContext testContext; public IUnitRunner(Class
klass) throws InitializationError { super(klass); //这个构造函数是junt的调用入口,这里我们把扩展功能的初始化写到其后 this.clazz = klass; this.testContext = new TestContext(); initListeners(); } private void initListeners(){ this.executeListeners.addAll(findListeners()); } /** * 解析为当前测试类注册的监听器 * @return */ @SuppressWarnings("rawtypes") private List
findListeners(){ List
result = new ArrayList
(); List
listeners = new ArrayList
(); Class
c = this.clazz; while(c != null){ IUnitTestExecuteListeners listener = c.getAnnotation(IUnitTestExecuteListeners.class); if(listener != null){ for(Class
l : listener.value()){ if(!listeners.contains(l)){ listeners.add(l); } } } c = c.getSuperclass(); } for(Class clazz:listeners){ try { result.add((IUnitTestExecuteListener) clazz.newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } return result; } @Override protected Object createTest() throws Exception { Object testInstance = super.createTest(); //加上我们框架的扩展功能 this.testContext.setTestInstance(testInstance); for(IUnitTestExecuteListener executeListener : this.executeListeners){ executeListener.prepareTestInstance(testContext); } return testInstance; } @Override protected void runChild(FrameworkMethod method, RunNotifier notifier) { EachTestNotifier eachNotifier= makeNotifier(method, notifier); if (method.getAnnotation(Ignore.class) != null) { runIgnored(eachNotifier); } else { runNotIgnored(method, eachNotifier); } } private EachTestNotifier makeNotifier(FrameworkMethod method, RunNotifier notifier) { Description description= describeChild(method); return new EachTestNotifier(notifier, description); } private void runIgnored(EachTestNotifier eachNotifier) { eachNotifier.fireTestIgnored(); } private void runNotIgnored(FrameworkMethod method, EachTestNotifier eachNotifier) { eachNotifier.fireTestStarted(); try { Statement statement = methodBlock(method); doBefore(); statement.evaluate(); doAfter(); } catch (AssumptionViolatedException e) { eachNotifier.addFailedAssumption(e); } catch (Throwable e) { eachNotifier.addFailure(e); testContext.setThrowable(e); doAfterThrowable(); } finally { eachNotifier.fireTestFinished(); } } private void doBefore()throws Exception{ for(IUnitTestExecuteListener executeListener : this.executeListeners){ executeListener.beforeTest(testContext); } } private void doAfter() throws Exception{ for(IUnitTestExecuteListener executeListener : this.executeListeners){ executeListener.afterTest(testContext); } } private void doAfterThrowable(){ for(IUnitTestExecuteListener executeListener : this.executeListeners){ try { executeListener.afterThrowable(testContext); } catch (Exception e) { e.printStackTrace(); } } }}

2.IUnitTestExecuteListener接口

这个接口定义了测试用例执行生命周期的几个关键点

package com.crazycoder2010.iunit;/** * 框架执行监听器 * @author Kevin * */public interface IUnitTestExecuteListener {	/**	 * TestCase对象被加载后执行的操作,每个TestCase只会执行一次	 * @param testContext	 */	public void prepareTestInstance(TestContext testContext) throws Exception;		/**	 * 在每执行一个单元测试方法之前运行	 * @param testContext	 * @throws Exception 	 */	public void beforeTest(TestContext testContext) throws Exception;		/**	 * 每个单元测试方法执行完时执行	 * @param testContext	 * @throws Exception 	 */	public void afterTest(TestContext testContext) throws Exception;		/**	 * 发生异常时做的处理	 * @param testContext	 */	public void afterThrowable(TestContext testContext) throws Exception;}
3.IUnitTestExecuteListeners注解

这个用来给测试类注册监听器的注解,一个IUnitTestExecuteListeners可以注册多个Listener

package com.crazycoder2010.iunit.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import com.crazycoder2010.iunit.IUnitTestExecuteListener;/** * 为TestCase注册监听器 *  * @author Kevin *  */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Inherited@Documentedpublic @interface IUnitTestExecuteListeners {	/**	 * 实际用到的监听器类	 * 	 * @return	 */	Class
[] value() default {};}
4.AbstractIUnitTestCase测试基类

这个类是为了便于测试定义了一个TestCase的基类,可以在此注册一些通用的监听器,注意@Runwith(IUnitRunner.class)这个是关键,否则我们写在runner中扩展的功能是不会被junit4执行到的

package com.crazycoder2010.iunit;import org.junit.runner.RunWith;import com.crazycoder2010.iunit.annotation.IUnitTestExecuteListeners;@RunWith(IUnitRunner.class)@IUnitTestExecuteListeners({DatasetProviderListener.class})public class AbstractIUnitTestCase {}

转载地址:http://zbkil.baihongyu.com/

你可能感兴趣的文章
Logtail提升采集性能
查看>>
史上最失败的一次营销活动
查看>>
asp.net5发神经一例 ------无法加载依赖
查看>>
数据库水平切分的实现原理解析
查看>>
nova boot from volume在多主机zone下的坑
查看>>
uip中关于web服务器的简单例子
查看>>
Windows 10 ADK 1809 的变更 附下载地址
查看>>
修改win7和win8 preview双系统的开机默认启动项
查看>>
关于PHP_CMS的一点感想
查看>>
知乎[披萨不就是个大饼铺点肉]问题延伸出的认知风格相关知识
查看>>
新浪微博基于混合云的PHP服务化与弹性扩容
查看>>
centOS7封装
查看>>
通过php 执行git pull 自动部署
查看>>
google乱码 IE浏览器 英文
查看>>
Linux查看系统配置常用命令
查看>>
销售型网站把握的设计要点
查看>>
我的友情链接
查看>>
mongodb数据备份和还原
查看>>
VM虚拟机下安装Centos7.0图文教程
查看>>
我的友情链接
查看>>