Junit4.12 source code analysis-runner execution sequence

Source: Internet
Author: User

Filter, sort

The runner must first filter and sort the execution. The default filter is all, indicating that all data passes through. The default sort is methodsorter's default

Parentrunner calls the filter and sort methods:

    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);        }    }

Sort methods in the methodsorter class:

    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 is the core of junit4's design. It adopts the responsibility chain mode. Each statement will reference a statement backward. The statement chain sequence is the execution sequence of the runner.

The runner calls classblock, implements methodblock first, constructs method-level statement chains, and then builds class-level statement chains.

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 first executes the current method, and then calls evaluate for the referenced statement. On the contrary, runafters calls evaluate for the referenced statement and then executes the current method. When runrules is initialized, apply all testrule, that is, put testrule into the statement chain.

Rule can be divided into @ classrule and @ rule, @ classrule is class-level, and @ rule is method-level. When the specific rule is executed, it depends on the sequence in which the statement chain calls evaluate in the apply method.

Regardless of rule and test class inheritance, after methodblock is executed, the statement chain is @ before-> @ test-> @ after. After classblock is executed, the statement chain is @ beforeclass-> @ before-> @ test-> @ After-> @ afterclass.

After methodblock is executed, the statement chain is the parent class @ before-> subclass @ before-> @ test-> subclass @ After-> parent class @ after, after classblock is executed, statement chain is the parent class @ beforeclass-> subclass @ beforeclass-> parent class @ before-> subclass @ before-> @ test-> subclass @ After-> parent class @ After-> subclass @ afterclass-> parent class @ 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;    }}

 

Junit4.12 source code analysis-runner execution sequence

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.