Junit使用及其原理分析
作者:
alighters 发布时间:
[ 2016/9/13 10:53:28 ] 推荐标签:
单元测试 Junit
其会调到一个 run(Runner runner) 的方法,而 Runner 是一个抽象类,其实现针对不同的平台又有好多个。这里主要提及两个,一个是 Junit4ClassRunner,它是 4.4 版本及之前的采用的,之后被废弃掉了,而采用了继承实现抽象类 ParentRunner 的 BlockJUnit4ClassRunner 类,它在 4.5 之后被采用。这里主要查看后者,先看 ParentRunner 对其接口 Runner 中方法 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.addFailedAssumption(e);
} catch (StoppedByUserException e) {
throw e;
} catch (Throwable e) {
testNotifier.addFailure(e);
}
}
其中,主要通过 classBlock 方法生成的 Statement 的 evaluate来进行调用,先看它是怎么生成的:
protected Statement classBlock(final RunNotifier notifier) {
Statement statement = childrenInvoker(notifier);
if (!areAllChildrenIgnored()) {
statement = withBeforeClasses(statement);
statement = withAfterClasses(statement);
statement = withClassRules(statement);
}
return statement;
}
这里主要的方法 childrenInvoker 会调用一个抽象的方法 protected abstract void runChild(T child, RunNotifier notifier);,它则是由子类来实现。另外看到的是,当测试类中的测试方法都没有被忽略的时候,则会使用 with对应的三个方法来添加其获取注解 BeforeClass,AfterClass,ClassRule对应的信息,并添加至其调用的 statement中。
接下来查看 BlockJUnit4ClassRunner 的 runChild的实现:
@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);
}
}
其中,若是添加了 @ignore的注解,则不会得到调用。看看 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);
}
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;
}
在这个 statement 的获取中,通过使用组合的方式,会这个 statement 添加 Before,After 及其它 Rule 的链式调用,后生成一个 statement 来返回。
总结
可以看出 Junit 是一个简单而又强大的库,不然不会经久不衰。其简单的实现但又强大的功能已经基本满足我们绝大多数的需求。但在这里还有一个疑问是不知道 Junit 是如何继承到 Android Studio 的 IDE 中,并是如何直接调用我们的测试方法或者测试类的?