`
jgnan
  • 浏览: 87548 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

JUnit 4.7学习笔记(二)——BlockJUnit4ClassRunner分析

阅读更多
前面提到过Junit的核心之一就是Runner,它是具体跑测试用例的人。自然我们就要先分析这个东西。通过Runner的层级视图我发现了不少新东西。不过我知道4.1版本的Runner核心就是org.junit.internal.runners.JUnit4ClassRunner这个类,所以我就先进去看看它的变化。结果发现它已经被deprecated了。而现在4.7取而代之的是我们上一次提到过的org.junit.runners.BlockJUnit4ClassRunner。

看一下这个类的层级图:

会发现它上面还有一个叫ParentRunner的东西,Runner接口的Run方法就是这个类实现的。

来看看这个Run方法:
@Override
public void run(final RunNotifier notifier) {
    EachTestNotifier testNotifier= new EachTestNotifier(notifier,getDescription());
    try {
        Statement statement= classBlock(notifier);
        statement.evaluate();
    } catch (AssumptionViolatedException e) {
        testNotifier.fireTestIgnored();
    } catch (StoppedByUserException e) {
        throw e;
    } catch (Throwable e) {
        testNotifier.addFailure(e);
    }
}

发现它所有的测试,现在是通过Statement类来调用的。看看classBlock(notifier)这个方法:
protected Statement classBlock(final RunNotifier notifier) {
    Statement statement= childrenInvoker(notifier);
    statement= withBeforeClasses(statement);
    statement= withAfterClasses(statement);
    return statement;
}


这个Statement会把一个测试会执行的所有方法都封装起来。其中从childrenInvoker这个方法命名来看,这次我们的junit会支持树级结构的测试哦,所以才会诞生了这次的ParentRunner。

来看看childrenInvoker方法及里面涉及到的一个runChildren:
protected Statement childrenInvoker(final RunNotifier notifier) {
    return new Statement() {
        @Override
        public void evaluate() {
            runChildren(notifier);
        }
    };
}

private void runChildren(final RunNotifier notifier) {
    for (final T each : getFilteredChildren())
        fScheduler.schedule(new Runnable() {			
            public void run() {
                ParentRunner.this.runChild(each, notifier);
            }
        });
    fScheduler.finished();
}


然后这个runChild(each,notifier)方法是由BlockJUnit4ClassRunner实现的:
@Override
protected void runChild(FrameworkMethod method, RunNotifier notifier) {
    //每个测试运行时会往里面添加测试结果,后期这些结果会汇总然后显示出来
    EachTestNotifier eachNotifier= makeNotifier(method, notifier);
    //如果发现测试方法上面带有@Ignore注解,就忽略这个测试方法
    if (method.getAnnotation(Ignore.class) != null) {
        eachNotifier.fireTestIgnored();
        return;
    }

    //通知测试引擎开始测试
    eachNotifier.fireTestStarted();
    try {
        //执行方法
        methodBlock(method).evaluate();
    } catch (AssumptionViolatedException e) {
        eachNotifier.addFailedAssumption(e);
    } catch (Throwable e) {
        eachNotifier.addFailure(e);
    } finally {
        //通知引擎测试已经完成
        eachNotifier.fireTestFinished();
    }
}


看看methodBlock:
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);
    }

    //测试结果封装为InvokeMethod
    Statement statement= methodInvoker(method, test);
    //如果有@expected的话,封装为ExpectException
    statement= possiblyExpectingExceptions(method, test, statement);
    //如果有@timeout的话,封装为FailOnTimeout
    statement= withPotentialTimeout(method, test, statement);
    //如果测试中带有有@Rule注解的字段,没有一个规则就会进行一次特定的监控
    statement= withRules(method, test, statement);
    //如果测试类带有@Before注解,封装为RunBefores
    statement= withBefores(method, test, statement);
    //如果测试类带有@After注解,封装为RunAfters
    statement= withAfters(method, test, statement);
    //返回结果
    return statement;
}

我发现除了传统的方法调用记过,ExpectException结果,RunBefores结果和RunAfters结果这些Statement对象外,还添加了Timeout和Rules的描述。Timeout就直接忽略了,这么简单应该大家都可以不言而喻,下面来重点研究一下这个前所未见的MethodRule规则。

明天继续,要去干其它事情了。。。
  • 大小: 11.5 KB
  • 大小: 9.8 KB
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

Global site tag (gtag.js) - Google Analytics