上一篇我们总体了解了下​​junit​​​框架的相关知识。这一篇我们将具体来分析相关的知识点。
我们将从以下几个方面来分析
1. ​​​junit​​​的运行流程
2. ​​​junit​​的主要类的具体分析。

junit的运行流程

为了更好的分析​​junit​​​的运行流程,我们先写一个测试类。
被测试类​​​Calculator​

/**
* Created by xiang.wei on 2018/3/21
*
* @author xiang.wei
*/
public class Calculator {
public int add(int a, int b) {
return a + b;
}

public int subtract(int a, int b) {
return a - b;
}

public int multiply(int a, int b) {
return a * b;
}

public int divide(int a, int b) {
return a / b;
}
}

测试类

import junit.framework.Assert;
import junit.framework.TestCase;

/**
* Created by xiang.wei on 2018/3/21
*
* @author xiang.wei
*/
public class CalculatorTest extends TestCase {

@Override
public void setUp() throws Exception {
System.out.println("测试开始");
}

public void testAdd()
{
Calculator calculator = new Calculator();
int result = calculator.add(1, 2);
// 判断方法的返回结果
Assert.assertEquals(3, result);// 第一个参数是期望值,第二个参数是要验证的值
}

public void testSubtract()
{
Calculator calculator = new Calculator();
int result = calculator.subtract(1, 2);
// 判断方法的返回结果
Assert.assertEquals(-1, result);// 第一个参数是期望值,第二个参数是要验证的值

}

public void testMultiply()
{
Calculator calculator = new Calculator();
int result = calculator.multiply(2, 3);
// 判断方法的返回结果
Assert.assertEquals(6, result);// 第一个参数是期望值,第二个参数是要验证的值

}

public void testDivide() {
Calculator calculator = new Calculator();
int result = calculator.divide(12, 3);
// 判断方法的返回结果
Assert.assertEquals(4, result);// 第一个参数是期望值,第二个参数是要验证的值
}
public void testFail(){
fail("失败测试");
}

@Override
public void tearDown() throws Exception {
System.out.println("测试结束");
}
}

测试结果:
Junit-3.8.1源码分析02----具体分析(执行流程)_返回结果
让我们通过断点调试来开始一段调试之路。
例如:要执行​​​testAdd​​​这个测试用例的话,中间到底要经历哪些过程呢?
1. 测试用例

public void testAdd()
{
Calculator calculator = new Calculator();
int result = calculator.add(1, 2);
// 判断方法的返回结果
Assert.assertEquals(3, result);// 第一个参数是期望值,第二个参数是要验证的值
}
  1. 入口程序 TestRunner类的doRun方法
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;
}
  1. ​TestCase​​​ 类的​​run​​方法
public abstract class TestCase extends Assert implements Test{
public void run(TestResult result) {
result.run(this);
}
}
  1. 调用​​TestResult​​​类的​​run​​方法,执行具体的测试用例
protected void run(final TestCase test) {
startTest(test);
Protectable p= new Protectable() {
public void protect() throws Throwable {
//具体运行测试用例,此处调用了TestCase类里的方法
test.runBare();
}
};
runProtected(test, p);

endTest(test);
}

// 一个测试用例开始前设置一些信息
public void startTest(Test test) {
final int count= test.countTestCases();
synchronized(this) {
fRunTests+= count;
}
for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) {
((TestListener)e.nextElement()).startTest(test);
}
}

PS: 具体执行测试用例的方法:

public abstract class TestCase extends Assert implements Test {

public void runBare() throws Throwable {
setUp();
try {
runTest();
}
finally {
tearDown();
}
}
/**
* Override to run the test and assert its state.
* @exception Throwable if any exception is thrown
*/
protected void runTest() throws Throwable {
assertNotNull(fName);
Method runMethod= null;
try {
// use getMethod to get all public inherited
// methods. getDeclaredMethods returns all
// methods of this class but excludes the
// inherited ones.
runMethod= getClass().getMethod(fName, null);
} catch (NoSuchMethodException e) {
fail("Method \""+fName+"\" not found");
}
if (!Modifier.isPublic(runMethod.getModifiers())) {
fail("Method \""+fName+"\" should be public");
}

try {
runMethod.invoke(this, new Class[0]);
}
catch (InvocationTargetException e) {
e.fillInStackTrace();
throw e.getTargetException();
}
catch (IllegalAccessException e) {
e.fillInStackTrace();
throw e;
}
}
}
  1. 最后一步,调用​​ResultPrinter​​​类的​​print​​方法,打印输出结果
synchronized void print(TestResult result, long runTime) {
printHeader(runTime);
printErrors(result);
printFailures(result);
printFooter(result);
}

总结:从上述源码中我们可以看出​​TestResult​​​和​​TestCase​​​直接存在双向依赖的联系。此处我觉得作者应该是为了提高代码的复用性。
​​​junit​​的介绍就到此为止,欢迎各位批评指正。