今天突然很想写JUnit的学习笔记,所以找回以前的文章接着写了:
自从JUnit上升到4.1版本之后,开始全面支持JDK1.5的Annotation。另外也重写了它的测试引擎,实现了测试引擎的可定制话。当时给我一个全新的测试体验,从来没想过原来写测试用例也可以这么好玩。
先看下面的例子:
package com.amway.training.junit.runners;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
/**
* A Demo Test Runner
* @author JJ
*
*/
public class DemoRunner extends Runner {
/**
* 核心引擎要求每个Runner类必须有一个这样的构造函数
* @param testClass 测试类
*/
public DemoRunner(Class<?> testClass)
{
}
@Override
public Description getDescription() {
return Description.EMPTY;
}
@Override
public void run(RunNotifier notifier) {
System.out.println("Hello, JUnit!");
}
}
然后写一个测试:
package com.amway.training.junit;
import org.junit.runner.RunWith;
import com.amway.training.junit.runners.DemoRunner;
@RunWith(DemoRunner.class)
public class TestDemoRunner {
}
运行这个单元测试,你会发现我们执行了DemoRunner的Run方法。说明我们现在可以改变测试运行的行为。
看了一下,发现4.7的这部分还是和4.1的时候发生了不少变化。首先,现在多了一个ParentRunner的类,它把Runner类再重新封装了一轮,并且让新的默认引擎类都继承于它。
上面的这些类就是4.7的Runner引擎家族。Junit38ClassRunner旁支是为了向下兼容3.8版本的测试用例。
IgnoredClassRunner会在测试引擎核心探测到测试文件的class有定义@Ignore注解的时候自动调用,它会跳过当前测试类的运行:
package com.amway.training.junit.runners;
import org.junit.Ignore;
import org.junit.Test;
@Ignore
public class TestIgnoredRunner {
@Test public void testMethod1()
{
System.out.println("Hello");
}
}
上例执行后,发觉运行结果并未对testMethod1进行执行。
而对于这部分的封装JUnit是通过Request机制来完成的。关于Request的介绍我们会在日后介绍(遥遥无期,遥遥无期。。。
)。
然后ErrorReportingRunner是在org.junit.internal包里面的,一般不会直接调用而是由系统的核心引擎去调用,所以它里面没有注释。我们来看看其源码以进行Runner的进一步学习:
首先,看其直接实现Runner的两个抽象方法:
@Override
public Description getDescription() {
Description description= Description.createSuiteDescription(fTestClass);
for (Throwable each : fCauses)
description.addChild(describeCause(each));
return description;
}
@Override
public void run(RunNotifier notifier) {
for (Throwable each : fCauses)
runCause(each, notifier);
}
然后可以知道其核心方法应该是runCause(Throwable,RunNotifier)
private void runCause(Throwable child, RunNotifier notifier) {
Description description= describeCause(child);
notifier.fireTestStarted(description);
notifier.fireTestFailure(new Failure(description, child));
notifier.fireTestFinished(description);
}
从字面看,可以知道这个测试引擎的主要工作就是把异常转换为Failure测试结果显示。以下是一个使用的例子:
try {
Runner runner= fRequest.getRunner();
fFilter.apply(runner);
return runner;
} catch (NoTestsRemainException e) {
return new ErrorReportingRunner(Filter.class, new Exception(String
.format("No tests found matching %s from %s", fFilter
.describe(), fRequest.toString())));
}
核心的BlockJUnit4ClassRunner就不说了,Theories会在日后说,因为这个模块是Junit开发团队用来做实验的,里面的东西不适宜用于生产,不过适宜拿来玩:)
今天到此为止,先开个头,下次再说ParentRunner及下面还没介绍到的子类(因为事忙,今天要写到这里了)