用JUnit4进行测试有两种方式分别是:
(1)、命令行方式:java org.junit.runner.JUnitCore [java class...];
(2)、程序方式:直接调用org.junit.runner.JUnitCore.runClass(Class>...clazz)方法;
这两种测试的方法,最终调用的是同一个执行体。先看第一种测试方法:在JUnitCore这个类中,我们可以发现它有一个main方法:
1 public static void main(String... args) { 2 runMainAndExit(new RealSystem(), args); 3 }
这就是命令行方式执行的入口,JUnitCore.runMain()方法
1 public Result runMain(JUnitSystem system, String... args) { 2 system.out().println("JUnit version " + Version.id()); 3 List> classes= new ArrayList >(); 4 List missingClasses= new ArrayList (); 5 for (String each : args) 6 try { 7 classes.add(Class.forName(each)); 8 } catch (ClassNotFoundException e) { 9 system.out().println("Could not find class: " + each); 10 Description description= Description.createSuiteDescription(each); 11 Failure failure= new Failure(description, e); 12 missingClasses.add(failure); 13 } 14 RunListener listener= new TextListener(system); 15 addListener(listener); 16 Result result= run(classes.toArray(new Class[0])); 17 for (Failure each : missingClasses) 18 result.getFailures().add(each); 19 return result; 20 }
在上面这个方法中,主要是构造一个存储Class>类型的List,以供JUnitCore.run(Class>...clazz);来执行。
再看第二种执行方式,调用的是JUnitCore.runClass(Class>... classes),
1 public static Result runClasses(Class>... classes) { 2 return new JUnitCore().run(defaultComputer(), classes); 3 }
在这个方法里面,会构造一个默认的Computer(这个后面会解释它的用处),紧接着就调用了JUnitCore的另外一个重载的run()方法
1 public Result run(Computer computer, Class>... classes) { 2 return run(Request.classes(computer, classes)); 3 }
该方法会构造一个封装了Runner的Request,然后继续调用JUnitCore的run方法:
1 public Result run(Runner runner) { 2 Result result= new Result(); 3 RunListener listener= result.createListener(); 4 fNotifier.addFirstListener(listener); 5 try { 6 fNotifier.fireTestRunStarted(runner.getDescription()); 7 runner.run(fNotifier); 8 fNotifier.fireTestRunFinished(result); 9 } finally { 10 removeListener(listener); 11 } 12 return result; 13 }
该方法才是真正的开始执行Test,首先会构造一个Result的对象,顾名思义就知道它是记录运行时的状态,
1 public class Result implements Serializable { 2 private static final long serialVersionUID = 1L; 3 private AtomicInteger fCount = new AtomicInteger(); 4 private AtomicInteger fIgnoreCount= new AtomicInteger(); 5 private final ListfFailures= Collections.synchronizedList(new ArrayList ()); 6 private long fRunTime= 0; 7 private long fStartTime; 8 //....... 9 private class Listener extends RunListener { 10 //....... 11 } 12 }
包括:所运行Test的数量,所忽略Test的数量,开始运行的时间,总运行时间,运行期间出现错误的信息;它里面还包含一个私有内部类,该类的作用就是帮助Result记录状态的。最后会执行Runner的run方法。这时就真正开始执行Test了。
这篇主要讲下JUnit是如何构建、运行Runner 。
JUnit4中是通过Request.classes(Computer computer, Class>... classes)来构造Runner的
//org.junit.runner.Request 1 public static Request classes(Computer computer, Class>... classes) { 2 try { 3 AllDefaultPossibilitiesBuilder builder= new AllDefaultPossibilitiesBuilder(true); 4 Runner suite= computer.getSuite(builder, classes); 5 return runner(suite); 6 } catch (InitializationError e) { 7 throw new RuntimeException( 8 "Bug in saff's brain: Suite constructor, called as above, should always complete"); 9 } 10 }
在上面这个方法中出现了一个重要的类,就是AllDefaultPossibilitiesBuilder,这个类就是用来选择RunerBuilder,继而选择Runner来执行Test。这个类中有一重要的方法runnerForClass(Class> testClass)(代码-1),
该方法用来确定选择RunerBuilder,继而选择Runner来执行Test。默认选择的是junit4Builder();(但是你可以自由选择和自己实现,可以用@RunWith Annotation来标注,这样就会选择annotatedBuilder()来作为RunnerBuilder.)。
在 选择好了RunnerBuilder后,接下就是要构建Runner了,这里是用Computer.getSuite()(代码-2)来获取Suite类型的 Runner(通过类层次关系,你会发现Suiter是继承自ParentRunner的,而ParentRunner是实现了Runner接口的)。
代码-1
//org.junit.internal.builders.AllDefaultPossibilitiesBuilder public Runner runnerForClass(Class> testClass) throws Throwable { Listbuilders= Arrays.asList( ignoredBuilder(), annotatedBuilder(), suiteMethodBuilder(), junit3Builder(), junit4Builder()); for (RunnerBuilder each : builders) { Runner runner= each.safeRunnerForClass(testClass); if (runner != null) return runner; } return null; }
代码-2
//org.junit.runners.Computer 1 public Runner getSuite(final RunnerBuilder builder, 2 Class>[] classes) throws InitializationError { 3 return new Suite(new RunnerBuilder() { 4 @Override 5 public Runner runnerForClass(Class> testClass) throws Throwable { 6 return getRunner(builder, testClass); 7 } 8 }, classes); 9 } 10 11 /** 12 * Create a single-class runner for {@code testClass}, using {@code builder} 13 */ 14 protected Runner getRunner(RunnerBuilder builder, Class> testClass) throws Throwable { 15 return builder.runnerForClass(testClass); 16 }
在上面的执行体中,只是new 出一个Suite对象然后返回。在Suite构造函数中接收两个参数(RunnerBuilder,Class>[]);仔细研究这段代码,你会发现这个新new出来的RunnerBuilder(第3行)的功能其实就是传进来的builder(第一行),也就是AllDefaultPossibilitiesBuilder对象;这样执行RunnerBuilder.runnerForClass(),方法时就是执行AllDefaultPossibilitiesBuilder.runnerForClass()方法。
再进入Suite的构造函数中,你会发现它调用了Runnerbuilder.runners方法,该方法的作用是获取suite的子集合。具体获取的实现就是调用AllDefaultPossibilitiesBuilder.runnerForClass(), 该方法默认会用JUnit4Builder();然后调用JUnit4Builder.runnerForClass();最后返回的是 BlockJUnit4ClassRunner对象,该对象和Suite是平级的也是继承自ParentRunner。(代码-3)演示了这个执行过程:
//org.junit.runners.Suite 1 public Suite(RunnerBuilder builder, Class>[] classes) throws InitializationError { 2 this(null, builder.runners(null, classes)); 3 }
代码-3
//org.junit.runners.model.RunnerBuilder 1 public Listrunners(Class> parent, Class>[] children) 2 throws InitializationError { 3 addParent(parent); 4 5 try { 6 return runners(children); 7 } finally { 8 removeParent(parent); 9 } 10 } 11 private List runners(Class>[] children) { 12 ArrayList runners= new ArrayList (); 13 for (Class> each : children) { 14 Runner childRunner= safeRunnerForClass(each); 15 if (childRunner != null) 16 runners.add(childRunner); 17 } 18 return runners; 19 } 20 21 public Runner safeRunnerForClass(Class> testClass) { 22 try { 23 return runnerForClass(testClass); 24 } catch (Throwable e) { 25 return new ErrorReportingRunner(testClass, e); 26 } 27 } 28 //org.junit.internal.builders.AllDefaultPossibilitiesBuilder 29 @Override 30 public Runner runnerForClass(Class> testClass) throws Throwable { 31 List builders= Arrays.asList( 32 ignoredBuilder(), 33 annotatedBuilder(), 34 suiteMethodBuilder(), 35 junit3Builder(), 36 junit4Builder()); 37 38 for (RunnerBuilder each : builders) { 39 Runner runner= each.safeRunnerForClass(testClass); 40 if (runner != null) 41 return runner; 42 } 43 return null; 44 } 45 //org.junit.internal.builders.AllDefaultPossibilitiesBuilder 46 protected JUnit4Builder junit4Builder() { 47 return new JUnit4Builder(); 48 } 49 public Runner runnerForClass(Class> testClass) throws Throwable { 50 return new BlockJUnit4ClassRunner(testClass); 51 }
构造完上面的子集合以后,就进行到Suite的另外一个构造函数中
//org.junit.runners.Suite 1 protected Suite(Class> klass, Listrunners) throws InitializationError { 2 super(klass); 3 fRunners = runners; 4 }
该构造函数中主要的功能就是调用父类的构造函数,在父类的构造函数中主要有以下功能:
1)、进行了部分方法的的验证,包括对BeforeClass和AfterClass所注解得方法进行了public static void 和无参数的判断和一些规则的判断。
2)、构造了一个TestClass(代码-4),这个类对Class对象进行了解析,把目标Class的方法和成员变量都解析出来了。并建立了一个从Annotation到方法和Annotation到成员变量的对应Map。
下面是ParentRunner的构造函数:
//org.junit.runners.ParentRunner 1 protected ParentRunner(Class> testClass) throws InitializationError { 2 fTestClass= new TestClass(testClass); 3 validate(); 4 }
1 private void validate() throws InitializationError { 2 Listerrors= new ArrayList (); 3 collectInitializationErrors(errors); 4 if (!errors.isEmpty()) 5 throw new InitializationError(errors); 6 }
1 protected void collectInitializationErrors(Listerrors) { 2 validatePublicVoidNoArgMethods(BeforeClass.class, true, errors); 3 validatePublicVoidNoArgMethods(AfterClass.class, true, errors); 4 validateClassRules(errors); 5 }
代码-4
//org.junit.runners.model.TestClass //Annotation到方法的对应 1 private Map, List > fMethodsForAnnotations= new HashMap , List >(); 2 //Annotation到成员变量的对应 3 private Map , List > fFieldsForAnnotations= new HashMap , List >(); 4 5 public TestClass(Class> klass) { 6 fClass= klass; 7 if (klass != null && klass.getConstructors().length > 1) 8 throw new IllegalArgumentException( 9 "Test class can only have one constructor"); 10 11 for (Class> eachClass : getSuperClasses(fClass)) { 12 for (Method eachMethod : eachClass.getDeclaredMethods()) 13 addToAnnotationLists(new FrameworkMethod(eachMethod), 14 fMethodsForAnnotations); 15 for (Field eachField : eachClass.getDeclaredFields()) 16 addToAnnotationLists(new FrameworkField(eachField), 17 fFieldsForAnnotations); 18 } 19 }
这样就成功构造了一个Runner对象(也就是Suite对象),接下了就是运行该Runner了。
1 public Result run(Runner runner) { 2 Result result= new Result(); 3 RunListener listener= result.createListener(); 4 fNotifier.addFirstListener(listener); 5 try { 6 fNotifier.fireTestRunStarted(runner.getDescription()); 7 runner.run(fNotifier); 8 fNotifier.fireTestRunFinished(result); 9 } finally { 10 removeListener(listener); 11 } 12 return result; 13 }
上面这个方法就是负责启动执行Runner的,他调用Runner.run()方法。也就是ParentRunner(Suite继承自ParentRunner,而Sutie没有对run方法进行重载)的run()方法。
再跟进到ParentRunner.run()方法中,这个方法的功能有:
1、构造一个链式的Statement,分别是:
RunRules --> RunAfters(@AfterClass) -->RunBefores(@BeforeClass) -->
(RunRules--> RunAfters(@After) -->RunBefores(@Before)-->FailOnTimeout(@Test(timeout=?))-->ExpectException(@Test(expect=?))-->InvokeMethod(@Test)...)-->
....
(RunRules--> RunAfters(@After) -->RunBefores(@Before)-->FailOnTimeout(@Test(timeout=?))-->ExpectException(@Test(expect=?))-->InvokeMethod(@Test)...);
从这个链式的结构中可以看出,最先执行的是RunRules这个Statement,然后是RunAfter(这里不要有疑问为什么先执行RunAfter,进去看看实现吧(代码2.1会揭晓一切的))...;
2、记录错误信息,在run方法中会传递进来一个RunNotifier对象,在这里RunNotifier可以拥有多个RunListener。默认的情况下在JunitCore里的RunNotifier只包含Result.RunListener对象,这样就可以进行对Result的状态的改变从而记录运行结果信息,其实这就是典型的观察者模式。RunNotifier就是观察者,得到通知就通知其子集合区执行相应的操作。
1 @Override 2 public void run(final RunNotifier notifier) { 3 EachTestNotifier testNotifier= new EachTestNotifier(notifier, 4 getDescription()); 5 try { 6 Statement statement= classBlock(notifier); 7 statement.evaluate(); 8 } catch (AssumptionViolatedException e) { 9 testNotifier.fireTestIgnored(); 10 } catch (StoppedByUserException e) { 11 throw e; 12 } catch (Throwable e) { 13 e.printStackTrace(); 14 testNotifier.addFailure(e); 15 } 16 }
1 protected Statement classBlock(final RunNotifier notifier) { 2 Statement statement= childrenInvoker(notifier); 3 statement= withBeforeClasses(statement); 4 statement= withAfterClasses(statement); 5 statement= withClassRules(statement); 6 return statement; 7 }
代码-2.1(RunAfter会先执行它的下一个,等它的下一个执行完成之后才执行本体。这样就可以保证呗@After和@AfterClass的注解的方法一定会被执行,即使某个环节执行过程出错也会执行finally的RunAfter本体);
1 public class RunAfters extends Statement { 2 private final Statement fNext; 3 4 private final Object fTarget; 5 6 private final ListfAfters; 7 8 public RunAfters(Statement next, List afters, Object target) { 9 fNext= next; 10 fAfters= afters; 11 fTarget= target; 12 } 13 14 @Override 15 public void evaluate() throws Throwable { 16 List errors = new ArrayList (); 17 try { 18 fNext.evaluate(); 19 } catch (Throwable e) { 20 errors.add(e); 21 } finally { 22 for (FrameworkMethod each : fAfters) 23 try { 24 each.invokeExplosively(fTarget); 25 } catch (Throwable e) { 26 errors.add(e); 27 } 28 }30 MultipleFailureException.assertEmpty(errors); 31 } 32 }
这样JUint的执行流程就讲完了。。。