设为首页 加入收藏

TOP

JUnit 源码解析(四)
2018-01-30 12:42:55 】 浏览:499
Tags:JUnit 源码 解析
atic的。

如上,我们分析了BlockJUnit4ClassRunner的运行流程,也就是说当测试类为一个的时候JUnit是如何工作的。前文也提到过,ParentRunner还有一个子类Suite,表示需要运行一组测试,BlockJUnit4ClassRunner的一个运行单元为FrameworkMethod,而Suite的一个运行单元为Runner,我们看其runChild方法:

protected void runChild(Runner runner, final RunNotifier notifier) {
    runner.run(notifier);
}

很是明了,直接滴啊用runner的run方法。这样,如果这个runner的实例仍然是Suite,则会继续向里运行,如果这个runner为BlockJUnit4ClassRunner,这执行我们前面分析的逻辑。这里有个问题是,那这个runner是如何生成的呢?这就要看Suite的构造函数:

protected Suite(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
        this(new AllDefaultPossibilitiesBuilder(true), klass, suiteClasses);
}

AllDefaultPossibilitiesBuilder的职责就是为每个类生找到对应的Runner,感兴趣可以查看其runnerForClass方法,比较容易理解,这里就不再赘述。

Matcher验证

上面我们分析了用@Test标注的函数是如何被JUnit执行的,但单单有@Test标注是肯定不够的,既然是测试,我们肯定需要一定的手段来验证程序的的执行是符合预期的。JUnit提供了Matcher机制,可以满足我们大部分的需求。Matcher相关类主要在org.hamcrest包下,先来看下类图:

上图仅仅列出了org.hamcrest包下的一部分类,这些类一起组合起来形成了JUnit强大的验证机制。

验证的基本写法是:

MatcherAssert.assertThat("saymagic", CoreMatchers.containsString("magic"));

首先我们需要调用的是MatcherAssert的assertThat方法,这个方法最终辗转为:

 public static <T> void assertThat(String reason, T actual, Matcher<? super T> matcher) {
        if (!matcher.matches(actual)) {
            Description description = new StringDescription();
            description.appendText(reason)
                       .appendText("\nExpected: ")
                       .appendDescriptionOf(matcher)
                       .appendText("\n     but: ");
            matcher.describeMismatch(actual, description);
            throw new AssertionError(description.toString());
        }
}

这个函数目的很是明确,直接判断matcher是否匹配,不匹配则封装描述信息,然后抛出异常。所以我们来关注matcher的matchs方法都做了些什么,CoreMatchers.containsString("magic")返回的就是一个matcher, CoreMatchers相当于一个静态工厂,提供了大量的静态方法来返回各种Matcher:

我们就已刚刚的containsString为例,查看其内部代码:

 public static org.hamcrest.Matcher<java.lang.String> containsString(java.lang.String substring) {
    return org.hamcrest.core.StringContains.containsString(substring);
  }

可见其调用了StringContains的一个静态方法,继续追:

@Factory
public static Matcher<String> containsString(String substring) {
   return new StringContains(substring);
}

这里很简单,直接new了一个StringContains实例,StringContains的继承关系如下:

首先BaseMatcher实现了Matcher接口,TypeSafeMatcher是BaseMatcher的一个抽象实现,它的matches方法如下:

public final boolean matches(Object item) {
   return item != null
           && expectedType.isInstance(item)
           && matchesSafely((T) item);
}

可见它在验证前作了判空与类型的校验,所以子类就可以实现matchesSafely方法,就无需在此方法中进行判空与类型的验证了。

SubstringMatchers是TypeSafeMatcher的一种实现,它是对字符串类验证的一种抽象,它的matchesSafely方法如下:

@Override
public boolean matchesSafely(String item) {
    return eva lSubstringOf(item);
}

子类需要实现eva lSubstringOf方法。如此,我们就可以看下StringContains的这个方法了:

 @Override
 protected boolean eva lSubstringOf(String s) {
     return s.indexOf(substring) >= 0;
 }

出奇的简单,并没有什么好解释的。这个如果返回了false,说明验证不通过,前面的assertThat方法就会抛出异常。这样,JUnit的一个测试就不会通过。

assert翻译过来为断言,也就是说,它是用来验证是非的,但我们也清楚,并非所有的事情都分是非,测试也如此,比如我们要测试登录模块,当点击login按钮的时候,可能验证通过后就跳转了页面,并没有任何返回值,这个时候我们往往会验证某个事情发生了,比如login后执行了跳转方法,这样就表示测试是通过的。这就是Mock框架来做的是。感兴趣的可以查看我的上一篇文章Mockito源码解析

总结

读懂JUnit的源码并不是很困难,我相信这与整体架构设计得当有关,使人读起来神清气爽。 此文也仅仅是对JUnit的源码粗略概括,更多的细节还有待大家仔细琢磨。

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

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目