JUnit4执行cases背后的故事(2)---默认执行器BlockJUnit4ClassRunner源码分析

(1)背景:

之前《JUnit4执行cases背后的故事(1)—JUnitCore源码分析》介绍了JUnit4执行测试用例默认的执行器是BlockJUnit4ClassRunner,它内部是怎么实现的呢? 本文将一一介绍。

(2)org.junit.runners.BlockJUnit4ClassRunner是什么?
官方解释如下:

it is now the default test class runner, but it should have exactly the same behavior as the old test class runner (JUnit4ClassRunner).

BlockJUnit4ClassRunner has advantages for writers of custom JUnit runners that are slight changes to the default behavior, however:

It has a much simpler implementation based on Statements, allowing new operations to be inserted into the appropriate point in the execution flow.
It is published, and extension and reuse are encouraged, whereas JUnit4ClassRunner was in an internal package, and is now deprecated.

概括来说:

BlockJUnit4ClassRunner是默认的测试类执行器,可以通过它方便地实现自定义执行器(可以在执行流中插入新的操作),它执行测试的方式是基于Statement block,Statement分成数种职责(BeforeClass, AfterClass,Before,After,执行测试方法等),不同的Statement负责自己的职责,执行结束后交给下一个Statement,直到所有Statement执行完毕;设计模式是职责链模式(Chain Of Responsibility Pattern)。

类继承关系:

java.lang.Object
  extended by org.junit.runner.Runner  
      extended by org.junit.runners.ParentRunner<FrameworkMethod>
          extended by org.junit.runners.BlockJUnit4ClassRunner
(3)源码分析

执行用例时,会执行runner.run(this.notifier);(见JUnit4执行cases背后的故事(1)—JUnitCore源码分析 第三部分),该runner为BlockJUnit4ClassRunner实例,调用其父类ParentRunner方法:

@Override
    public void run(final RunNotifier notifier) {
        EachTestNotifier testNotifier = new EachTestNotifier(notifier,
                getDescription());
        try {
            Statement statement = classBlock(notifier);
            statement.evaluate();
        } catch (AssumptionViolatedException e) {
            testNotifier.addFailedAssumption(e);
        } catch (StoppedByUserException e) {
            throw e;
        } catch (Throwable e) {
            testNotifier.addFailure(e);
        }
    }

run()方法调用classBlock(notifier)新建Statement实例(类Statement block)。

protected Statement classBlock(final RunNotifier notifier) {
        Statement statement = childrenInvoker(notifier);
        if (!areAllChildrenIgnored()) {
            statement = withBeforeClasses(statement);
            statement = withAfterClasses(statement);
            statement = withClassRules(statement);
        }
        return statement;
    }

classBlocke()方法调用childrenInvoker()新建Statement实例(方法Statement block)

protected Statement childrenInvoker(final RunNotifier notifier) {
        return new Statement() {
            @Override
            public void evaluate() {
                runChildren(notifier);
            }
        };
    }

childrenInvoker()新建Statement实例,该实例重写evaluate()方法,runChildren()定义测试方法将要执行的调度策略。

private void runChildren(final RunNotifier notifier) {
        final RunnerScheduler currentScheduler = scheduler;
        try {
            for (final T each : getFilteredChildren()) {
                currentScheduler.schedule(new Runnable() {
                    public void run() {
                        ParentRunner.this.runChild(each, notifier);
                    }
                });
            }
        } finally {
            currentScheduler.finished();
        }
    }

getFilteredCildren()返回List<FrameworkMethod>, 每个FrameworkMethod实例是@Test标记的测试方法。
getFilteredCildren()方法内部通过getChildren(),computeTestMethods()获取到List。

protected List<FrameworkMethod> getChildren() {
        return computeTestMethods();
    }


protected List<FrameworkMethod> computeTestMethods() {
        return getTestClass().getAnnotatedMethods(Test.class);
    }

runChildren()遍历List<FrameworkMethod>, 对每个FrameworkMethod调用BlockJUnit4ClassRunner的runChild()作为RunnerScheduler currentScheduler实例(RunnerScheduler:Represents a strategy for scheduling when individual test methods should be run (in serial or parallel))的执行体:

 @Override
    protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
        Description description = describeChild(method);
        if (isIgnored(method)) {
            notifier.fireTestIgnored(description);
        } else {
            Statement statement;
            try {
                statement = methodBlock(method);
            }
            catch (Throwable ex) {
                statement = new Fail(ex);
            }
            runLeaf(statement, description, notifier);
        }
    }

如果该方法未被标记@Ignore,则获取到该方法的Statement:

protected Statement methodBlock(final FrameworkMethod method) {
        Object test;
        try {
            test = new ReflectiveCallable() {
                @Override
                protected Object runReflectiveCall() throws Throwable {
                    return createTest(method);
                }
            }.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;
    }

methodInvoker()方法会新建InvokeMethod实例(Statement子类),InvokeMethod类重写evaluate()方法。

protected Statement methodInvoker(FrameworkMethod method, Object test) {
        return new InvokeMethod(method, test);
    }
public class InvokeMethod extends Statement {
    private final FrameworkMethod testMethod;
    private final Object target;

    public InvokeMethod(FrameworkMethod testMethod, Object target) {
        this.testMethod = testMethod;
        this.target = target;
    }

    @Override
    public void evaluate() throws Throwable {
        testMethod.invokeExplosively(target);
    }
}

evaluate()执行体testMethod.invokeExplosively(target), target值为test,invokeExplosively()方法返回@Test测试方法的执行结果。

/**
     * Returns the result of invoking this method on {@code target} with
     * parameters {@code params}. {@link InvocationTargetException}s thrown are
     * unwrapped, and their causes rethrown.
     */
    public Object invokeExplosively(final Object target, final Object... params)
            throws Throwable {
        return new ReflectiveCallable() {
            @Override
            protected Object runReflectiveCall() throws Throwable {
                return method.invoke(target, params);
            }
        }.run();
    }

runChild()调用父类ParentRunner的runLeaf()方法(方法Statement block部分)并执行该Statement block(通过statement.evaluate());

/**
     * Runs a {@link Statement} that represents a leaf (aka atomic) test.
     */
    protected final void runLeaf(Statement statement, Description description,
            RunNotifier notifier) {
        EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description);
        eachNotifier.fireTestStarted();
        try {
            statement.evaluate();
        } catch (AssumptionViolatedException e) {
            eachNotifier.addFailedAssumption(e);
        } catch (Throwable e) {
            eachNotifier.addFailure(e);
        } finally {
            eachNotifier.fireTestFinished();
        }
    }

通过Statement statement = childrenInvoker(notifier)获取method Statem block后,再获取class Statement block。

            statement = withBeforeClasses(statement);
            statement = withAfterClasses(statement);
            statement = withClassRules(statement);

最后调用:statement.evaluate();依次执行evaluate()…

@Override
    public void run(final RunNotifier notifier) {
        EachTestNotifier testNotifier = new EachTestNotifier(notifier,
                getDescription());
        try {
            Statement statement = classBlock(notifier);
            statement.evaluate();
(4)总结
1.如果想在class Statement block加入自定义动作,可以修改classBlock()方法。
2.如果想在method Statement block加入自定义动作,可以修改methodBlock()方法。
3.如果想在@Test方法加入自定义动作,可以修改methodInvoker()方法。

所有修改必须定义一个Statement子类,并重写evaluate()方法定义自己的职责。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
powermock-module-junit4-common是PowerMock框架中的一个模块,用于与JUnit4集成。这个模块可以在测试过程中模拟和修改静态方法、私有方法、构造函数和final类等。当我们需要对这些难以测试的代码进行单元测试时,可以使用这个模块来解决这个问题。 要下载powermock-module-junit4-common,需要先确保在项目的构建工具中引入了PowerMock框架的依赖。如果使用Maven进行构建,可以在pom.xml文件中添加以下依赖: <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4-common</artifactId> <version>版本号</version> <scope>test</scope> </dependency> 在Gradle中,可以在build.gradle文件的dependencies部分添加以下代码: testImplementation 'org.powermock:powermock-module-junit4-common:版本号' 在配置好依赖之后,再执行构建工具的相关命令,即可自动下载并引入powermock-module-junit4-common模块。 通过使用powermock-module-junit4-common,我们可以更方便地编写单元测试,尤其适用于需要模拟静态方法、私有方法或者处理final类的情况。它为我们提供了更多的测试可能性,使得我们能够更全面地覆盖代码并提高测试覆盖率。同时,它也提供了一系列好用的工具类和注解,让测试代码编写更加简洁高效。 总之,下载并使用powermock-module-junit4-common模块可以为我们提供更强大的测试能力,帮助我们更好地进行单元测试。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值