Junit介绍
Junit 是由 Erich Gamma 和 Kent Beck 编写的一个开源的单元测试框架,主要用于白盒测试。Junit 的设计精简,易学易用,但是功能却非常强大。
在Junit3中,使用时只需继承TestCase类,并且
1. 测试方法名以test开头,返回void,方法中没有参数
2. 使用方法setUp()做初始化工作,使用方法tearDown()做清理工作
3. 使用Assert类的方法来判断测试用例结果
Junit源码分析
Junit的流程图:
Junit的完整生命周期分为 3 个阶段:初始化阶段、运行阶段和结果打印输出阶段。
1. 初始化阶段
Junit的入口函数是TestRunner.java的main(),
它主要是创建TestRunner实例和调用TestRunner的start()方法。
public static void main(String[] args) {
TestRunner aTestRunner = new TestRunner();
try {
TestResult r = aTestRunner.start(args);
if (!r.wasSuccessful()) {
System.exit(FAILURE_EXIT);
}
System.exit(SUCCESS_EXIT);
} catch (Exception e) {
System.err.println(e.getMessage());
System.exit(EXCEPTION_EXIT);
}
}
在start()方法中,首先对命令行进行解析(-wait 等待执行 -c 指定测试类 -m 指定测试类中的测试方法 -v 打印出Junit版本信息),然后加载所有的测试方法,最后调用doRun()方法,进入Junit的运行阶段。
public TestResult start(String[] args) throws Exception {
String testCase = "";
String method = "";
boolean wait = false;
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-wait")) {
wait = true;
} else if (args[i].equals("-c")) {
testCase = extractClassName(args[++i]);
} else if (args[i].equals("-m")) {
String arg = args[++i];
int lastIndex = arg.lastIndexOf('.');
testCase = arg.substring(0, lastIndex);
method = arg.substring(lastIndex + 1);
} else if (args[i].equals("-v")) {
System.err.println("JUnit " + Version.id() + " by Kent Beck and Erich Gamma");
} else {
testCase = args[i];
}
}
... ...
try {
... ...
Test suite = getTest(testCase);
return doRun(suite, wait);
} catch (Exception e) {
throw new Exception("Could not create and run test suite: " + e);
}
}
2. Junit的运行阶段
在初始化阶段最后,代码进入doRun()方法,它会
初始化TestResult,并将PrintResult的实例fPrinter加入到TestRunner的监听列表中,最后调用TestSuite的run()方法。
public TestResult doRun(Test suite, boolean wait) {
TestResult result = createTestResult();
result.addListener(fPrinter);
long startTime = System.currentTimeMillis();
suite.run(result);
long endTime = System.currentTimeMillis();
long runTime = endTime - startTime;
fPrinter.print(result, runTime);
pause(wait);
return result;
}
TestSuite中存放了TestCase列表:
private Vector<Test> fTests = new Vector<Test>(10);
运行流程图为:
TestCase的runBare()将会正式进入到测试类中:
1. 调用测试类的setUp()方法,进行测试前的初始化工作
2. 调用测试类的testXXX()方法,进行测试
3. 捕获测试中发生的异常
4. 调用测试类的tearDown()方法,进行测试后的清理工作
5. 捕获tearDown()中发生的异常
6. 抛出异常
public void runBare() throws Throwable {
Throwable exception = null;
setUp();
try {
runTest();
} catch (Throwable running) {
exception = running;
} finally {
try {
tearDown();
} catch (Throwable tearingDown) {
if (exception == null) exception = tearingDown;
}
}
if (exception != null) throw exception;
}
3. 结果打印输出阶段
TestResult的runProtected()用于捕获测试用例的
异常输出,当捕获到
AssertionFailedError异常时,判断测试用例运行失败,将异常信息加入到fFailures
列表中;当捕获到Throwable异常时,判断测试用例运行失败,将异常信息加入到fErrors列表中。
public void runProtected(final Test test, Protectable p) {
try {
p.protect();
} catch (AssertionFailedError e) {
addFailure(test, e);
} catch (ThreadDeath e) { // don't catch ThreadDeath by accident
throw e;
} catch (Throwable e) {
addError(test, e);
}
}
public synchronized void addFailure(Test test, AssertionFailedError e) {
fFailures.add(new TestFailure(test, e));
for (TestListener each : cloneListeners()) {
each.addFailure(test, e);
}
}
public synchronized void addError(Test test, Throwable e) {
fErrors.add(new TestFailure(test, e));
for (TestListener each : cloneListeners()) {
each.addError(test, e);
}
}
最后,TestRunner调用ResultPrinter的print()方法打印出测试用例的运行结果。
synchronized void print(TestResult result, long runTime) {
printHeader(runTime);
printErrors(result);
printFailures(result);
printFooter(result);
}
参考博文:分析JUnit框架源代码 https://www.ibm.com/developerworks/cn/java/j-lo-junit-src/