filter、sort
runner执行要先过滤和排序。默认的filter是ALL代表全部通过,默认的排序是MethodSorter的DEFAULT
ParentRunner调用filter和sort方法:
public void filter(Filter filter) throws NoTestsRemainException { synchronized (childrenLock) { List<T> children = new ArrayList<T>(getFilteredChildren()); for (Iterator<T> iter = children.iterator(); iter.hasNext(); ) { T each = iter.next(); if (shouldRun(filter, each)) { try { filter.apply(each); } catch (NoTestsRemainException e) { iter.remove(); } } else { iter.remove(); } } filteredChildren = Collections.unmodifiableCollection(children); if (filteredChildren.isEmpty()) { throw new NoTestsRemainException(); } } } public void sort(Sorter sorter) { synchronized (childrenLock) { for (T each : getFilteredChildren()) { sorter.apply(each); } List<T> sortedChildren = new ArrayList<T>(getFilteredChildren()); Collections.sort(sortedChildren, comparator(sorter)); filteredChildren = Collections.unmodifiableCollection(sortedChildren); } }
MethodSorter类实现method的排序:
public static final Comparator<Method> DEFAULT = new Comparator<Method>() { public int compare(Method m1, Method m2) { int i1 = m1.getName().hashCode(); int i2 = m2.getName().hashCode(); if (i1 != i2) { return i1 < i2 ? -1 : 1; } return NAME_ASCENDING.compare(m1, m2); } };
statement、rule
statement是junit4设计的核心,采用责任链模式,每个statement都会向后引用一个statement,statement链先后顺序就是runner的执行顺序。
runner中调用classBlock,先进行methodBlock,方法级别的statement链构建,然后再进行class级别的statement链构建
ParentRunner: protected Statement classBlock(final RunNotifier notifier) { Statement statement = childrenInvoker(notifier); if (!areAllChildrenIgnored()) { statement = withBeforeClasses(statement); statement = withAfterClasses(statement); statement = withClassRules(statement); } return statement; } BlockJUnit4ClassRunner: protected Statement methodBlock(FrameworkMethod method) { Object test; try { test = new ReflectiveCallable() { @Override protected Object runReflectiveCall() throws Throwable { return createTest(); } }.run(); } catch (Throwable e) { return new Fail(e); } Statement statement = methodInvoker(method, test); statement = possiblyExpectingExceptions(method, test, statement); statement = withPotentialTimeout(method, test, statement); statement = withBefores(method, test, statement); statement = withAfters(method, test, statement); statement = withRules(method, test, statement); return statement; }
RunBefores、RunAfters、RunRules
RunBefores先执行当前方法,再对引用的statement调用evaluate。RunAfters相反,先对引用的statement调用evaluate,再执行当前方法。RunRules初始化时apply所有TestRule,就是把TestRule放到statement链。
Rule分为@ClassRule和@Rule,@ClassRule是类级别的,@Rule是方法级别的。具体的rule在何时执行要看apply方法中statement链调用evaluate的先后。
不考虑rule和测试类继承,执行完methodBlock后,statement链是@Before->@Test->@After,classBlock执行完后,statement链是@BeforeClass->@Before->@Test->@After->@AfterClass。
不考虑rule,执行完methodBlock后,statement链是父类@Before->子类@Before->@Test->子类@After->父类@After,classBlock执行完后,statement链是父类@BeforeClass->子类@BeforeClass->父类@Before->子类@Before->@Test->子类@After->父类@After->子类@AfterClass->父类@AfterClass
public class RunBefores extends Statement { private final Statement next; private final Object target; private final List<FrameworkMethod> befores; public RunBefores(Statement next, List<FrameworkMethod> befores, Object target) { this.next = next; this.befores = befores; this.target = target; } @Override public void evaluate() throws Throwable { for (FrameworkMethod before : befores) { before.invokeExplosively(target); } next.evaluate(); } } public class RunAfters extends Statement { private final Statement next; private final Object target; private final List<FrameworkMethod> afters; public RunAfters(Statement next, List<FrameworkMethod> afters, Object target) { this.next = next; this.afters = afters; this.target = target; } @Override public void evaluate() throws Throwable { List<Throwable> errors = new ArrayList<Throwable>(); try { next.evaluate(); } catch (Throwable e) { errors.add(e); } finally { for (FrameworkMethod each : afters) { try { each.invokeExplosively(target); } catch (Throwable e) { errors.add(e); } } } MultipleFailureException.assertEmpty(errors); } } public class RunRules extends Statement { private final Statement statement; public RunRules(Statement base, Iterable<TestRule> rules, Description description) { statement = applyAll(base, rules, description); } @Override public void evaluate() throws Throwable { statement.evaluate(); } private static Statement applyAll(Statement result, Iterable<TestRule> rules, Description description) { for (TestRule each : rules) { result = each.apply(result, description); } return result; } }