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)飛哥