设为首页 加入收藏

TOP

JUnit 源码解析(二)
2018-01-30 12:42:55 】 浏览:498
Tags:JUnit 源码 解析
methodsForAnnotations); } // ensuring fields are sorted to make sure that entries are inserted // and read from fieldForAnnotations in a deterministic order for (Field eachField : getSortedDeclaredFields(eachClass)) { addToAnnotationLists(new FrameworkField(eachField), fieldsForAnnotations); } } }

整个函数的作用就是扫描class中方法和变量上的注解,并将其根据注解的类型进行分类,缓存在methodsForAnnotations与fieldsForAnnotations当中。需要注意的是,JUnit对方法和变量分别封装为FrameworkMethod与FrameworkField,它们都继承自FrameworkMember,这样就为方法和变量进行了统一抽象。

看完了ParentRunner的构造函数,我们来看ParentRunner继承自Runner的run方法是如何工作的:

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

其中比较关键的代码是classBlock函数将notifier转换为Statement:

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

继续追进childrenInvoker之前,允许我现在这里先存个档,记为A,一会我们会回到classBlock这里

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

childrenInvoker返回的是一个Statement,看它的eva luate方法,其调用的是runChildren方法,这也是ParentRunner中非常重要的一个函数:

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

这个函数就体现了抽象的重要性,注意泛型T,它在ParentRunner的每个实现类中各不相同,在BlockJUnit4ClassRunner中T表示FrameworkMethod,具体到这个函数来讲getFilteredChildren拿到的是被@Test注解标注的FrameworkMethod,而在Suite中,T为Runner,而ParentRunner.this.runChild(each, notifier);这句的中的runChild(each, notifier)方法依旧是个抽象方法,我们先看BlockJUnit4ClassRunner中的实现:

@Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
     Description description = describeChild(method);
     if (isIgnored(method)) {
         notifier.fireTestIgnored(description);
     } else {
         runLeaf(methodBlock(method), description, notifier);
     }
}

isIgnored方法判断了method方法是否被@Ignore注解标识,如果是的话则直接通知notifier触发ignored事件,否则,执行runLeaf方法, runLeaf的第一个参数是Statement,所以,BlockJUnit4ClassRunner通过methodBlock方法将method转换为Statement:

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);
首页 上一页 1 2 3 4 下一页 尾页 2/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇JUnit 源码解析 下一篇理解 Consistent Hashing

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目