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 List2.IUnitTestExecuteListener接口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(); } } }}
这个接口定义了测试用例执行生命周期的几个关键点
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 {}