Junit-3.8.1源碼分析02----具體分析(執(zhí)行流程)

上一篇我們總體了解了下junit框架的相關(guān)知識。這一篇我們將具體來分析相關(guān)的知識點。
我們將從以下幾個方面來分析
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);
        // 判斷方法的返回結(jié)果
        Assert.assertEquals(3, result);// 第一個參數(shù)是期望值,第二個參數(shù)是要驗證的值
    }

    public void testSubtract()
    {
        Calculator calculator = new Calculator();
        int result = calculator.subtract(1, 2);
        // 判斷方法的返回結(jié)果
        Assert.assertEquals(-1, result);// 第一個參數(shù)是期望值,第二個參數(shù)是要驗證的值

    }

    public void testMultiply()
    {
        Calculator calculator = new Calculator();
        int result = calculator.multiply(2, 3);
        // 判斷方法的返回結(jié)果
        Assert.assertEquals(6, result);// 第一個參數(shù)是期望值,第二個參數(shù)是要驗證的值

    }

    public void testDivide() {
        Calculator calculator = new Calculator();
        int result = calculator.divide(12, 3);
        // 判斷方法的返回結(jié)果
        Assert.assertEquals(4, result);// 第一個參數(shù)是期望值,第二個參數(shù)是要驗證的值
    }
    public void testFail(){
        fail("失敗測試");
    }

    @Override
    public void tearDown() throws Exception {
        System.out.println("測試結(jié)束");
    }
}



測試結(jié)果:
測試結(jié)果
讓我們通過斷點調(diào)試來開始一段調(diào)試之路。
例如:要執(zhí)行testAdd這個測試用例的話,中間到底要經(jīng)歷哪些過程呢?
1. 測試用例

    public void testAdd()
    {
        Calculator calculator = new Calculator();
        int result = calculator.add(1, 2);
        // 判斷方法的返回結(jié)果
        Assert.assertEquals(3, result);// 第一個參數(shù)是期望值,第二個參數(shù)是要驗證的值
    }



    入口程序 TestRunner類的doRun方法

public TestResult doRun(Test suite, boolean wait) {
        TestResult result= createTestResult();
        //添加抽象觀察者
        result.addListener(fPrinter);
        long startTime= System.currentTimeMillis();
        //執(zhí)行測試用例
        suite.run(result);
        long endTime= System.currentTimeMillis();
        long runTime= endTime-startTime;
        //打印結(jié)果
        fPrinter.print(result, runTime);

        pause(wait);
        return result;
    }



    TestCase 類的run方法

public abstract class TestCase extends Assert implements Test{
    public void run(TestResult result) {
        result.run(this);
    }
}

 

    調(diào)用TestResult類的run方法,執(zhí)行具體的測試用例

    protected void run(final TestCase test) {
        startTest(test);
        Protectable p= new Protectable() {
            public void protect() throws Throwable {
                //具體運行測試用例,此處調(diào)用了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: 具體執(zhí)行測試用例的方法:

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;
        }
    }
 }


    最后一步,調(diào)用ResultPrinter類的print方法,打印輸出結(jié)果

    synchronized void print(TestResult result, long runTime) {
        printHeader(runTime);
        printErrors(result);
        printFailures(result);
        printFooter(result);
    }

 

總結(jié):從上述源碼中我們可以看出TestResult和TestCase直接存在雙向依賴的聯(lián)系。此處我覺得作者應該是為了提高代碼的復用性。
junit的介紹就到此為止,歡迎各位批評指正。


作者:碼農(nóng)飛哥
微信公眾號:碼農(nóng)飛哥