junit4.12源码分析-runner执行顺序

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;
    }
}
时间: 2024-11-12 15:28:03

junit4.12源码分析-runner执行顺序的相关文章

junit4.12源码分析-启动到选择runner

第一次写源代码分析,介绍运行流程和其中重要的类和接口! JUnitCore JUnitCore采用门面模式,可以启动junit4,junit3测试,也可以测试指定class.JUnitCore声明RunNotifier类,该类采用观察者模式实现事件管理.RunListener为测试事件基类,有测试开始结束失败等事件,如果想自定义事件可以继承该类.默认增加了两个RunListener,一个是TextListener,另一个是Result类函数createListener构造的Listener用于记

【JUnit4.10源码分析】6.1 排序和过滤

abstract class ParentRunner<T> extends Runner implements Filterable,Sortable 本节介绍排序和过滤. (尽管JUnit4.8.2源码分析-6.1 排序和过滤中演示了客户使用排序和过滤的方式,也有些不明确其设计意图.可是.先读懂源码为妙.说不定看着看着就明确了. ) org.junit.runner.manipulation包 排序和过滤的相关类型.在org.junit.runner.manipulation包中.Sort

深入源码分析SpringMVC执行过程

本文主要讲解 SpringMVC 执行过程,并针对相关源码进行解析. 首先,让我们从 Spring MVC 的四大组件:前端控制器(DispatcherServlet).处理器映射器(HandlerMapping).处理器适配器(HandlerAdapter)以及视图解析器(ViewResolver) 的角度来看一下 Spring MVC 对用户请求的处理过程,过程如下图所示: SpringMVC 执行过程 用户请求发送到前端控制器 DispatcherServlet. 前端控制器 Dispat

yii2源码分析之执行基本流程

用yii2框架用了将近2年,一直都没有去看过它底层源码,  马上快不用了,最近对其源码研究一番,哈哈 废话少说,上代码, 入口文件是web/index.php <?php defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_ENV') or define('YII_ENV', 'dev'); //这行我在composer autoload流程已经分析过 require __DIR__ . '/../vendor/auto

knockout源码分析之执行过程

一.执行流程 二.主要类分析 2.1. 在applyBindings中,创建bindingContext,然后执行applyBindingsToNodeAndDescendantsInternal方法2.2. 在applyBindinsToNodeAndDescendantsInteranl方法,主要完成当前Node的绑定,以及子Node的绑定 function applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVeri

【JUnit4.10源码分析】5.2 Rule

标注@Rule TestRule是一个工厂方法模式中的Creator角色--声明工厂方法. package org.junit.rules; import org.junit.runner.Description; import org.junit.runners.model.Statement; public interface TestRule { Statement apply(Statement base, Description description); } 因为工厂方法apply有

JUnit4.8.2源码分析-1 说明

阅读本系列文章时须要知道的: JUnit是由GOF 之中的一个的Erich Gamma和 Kent Beck 编写的一个开源的单元測试框架,分析JUnit源码的主要目的是学习当中对设计模式的运用.JUnit也是一个研究怎样应对版本号升级和接口变化的案例. 链接1:源码分析 JUnit4.8.2源码分析-1单元測试类 JUnit4.8.2源码分析-2 Request和Description JUnit4.8.2源码分析-3 TestClass 和RunnerBuilder JUnit4.8.2源码

Struts2 源码分析——调结者(Dispatcher)之执行action

章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行action呢?本章笔者就带大家来看看StrutsExecuteFilter类的工作.在理解StrutsExecuteFilter类的工作之前,笔者还是希望大家回顾一下前一章讲到的request请求工作.为什么这样子讲呢?可以说StrutsExecuteFilter类的工作是建立在StrutsPrep

Docker源码分析(二):Docker Client创建与命令执行

1. 前言 如今,Docker作为业界领先的轻量级虚拟化容器管理引擎,给全球开发者提供了一种新颖.便捷的软件集成测试与部署之道.在团队开发软件时,Docker可以提供可复用的运行环境.灵活的资源配置.便捷的集成测试方法以及一键式的部署方式.可以说,Docker的优势在简化持续集成.运维部署方面体现得淋漓尽致,它完全让开发者从持续集成.运维部署方面中解放出来,把精力真正地倾注在开发上. 然而,把Docker的功能发挥到极致,并非一件易事.在深刻理解Docker架构的情况下,熟练掌握Docker C