补:Junit3执行流程分析
1、TestRunner 入口点。生成TestRunner实例,首先执行TestRunner的main方法。
public static void main(String args[]) {
TestRunner aTestRunner= new TestRunner();
try {
//args参数指定的测试类的名称
TestResult r= aTestRunner.start(args);
} catch(Exception e) {}
}
2、构造生成TestSuite 。suite的概念在于,一个测试类存在多个测试方法,将所有的测试方法抽取存储于一个集合,遍历执行对应操作。
/**
* Starts a test run. Analyzes the command line arguments and runs the given
* test suite.
*/
public TestResult start(String args[]) throws Exception {
String testCase= args[i]; // 赋值“测试类”名称
String method= "";
boolean wait= false;
try {
//判断是否执行单个方法的测试
if (!method.equals(""))
return runSingleMethod(testCase, method, wait);
//构造生成TestSuite
Test suite= getTest(testCase);
//执行测试
return doRun(suite, wait);
} catch (Exception e) {}
}
3、TestRunner继承BaseTestRunner,getTest()是BaseTestRunner定义的一个模版方法
/**
* Returns the Test corresponding to the given suite. This is
* a template method, subclasses override runFailed(), clearStatus().
*/
public Test getTest(String suiteClassName) {
Class testClass= null;
try {
//根据类名加载“测试类”
testClass= loadSuiteClass(suiteClassName);
} catch (ClassNotFoundException e) {}
catch(Exception e) {}
Method suiteMethod= null;
try {
//Junit3中可以自定义suite()方法,根据反射尝试获取suite方法对于的Method类
suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]);
} catch(Exception e) {
// try to extract a test suite automatically
clearStatus();
//若不存在suite方法,则构造Junit自动构造测试方法集合suite,返回。
return new TestSuite(testClass);
}
}
4、正式构造TestSuite
/**
* Constructs a TestSuite from the given class. Adds all the methods
* starting with "test" as test cases to the suite.
*/
public TestSuite(final Class theClass) {
fName= theClass.getName();
Class superClass= theClass;
Vector names= new Vector();
//遍历方法,判断是否为“需要测试”方法,构造
while (Test.class.isAssignableFrom(superClass)) {
Method[] methods= superClass.getDeclaredMethods();
for (int i= 0; i < methods.length; i++) {
addTestMethod(methods[i], names, theClass);
}
//获取到“父”类,一层层的向上遍历,找寻“Test”方法,添加到TestSuite
superClass= superClass.getSuperclass();
}
if (fTests.size() == 0)
addTest(warning("No tests found in "+theClass.getName()));
}
private void addTestMethod(Method m, Vector names, Class theClass) {
String name= m.getName();
//判断出来,添加进MethodName的集合names
if (names.contains(name))
return;
if (! isPublicTestMethod(m)) {
if (isTestMethod(m))
addTest(warning("Test method isn't public: "+m.getName()));
return;
}
names.addElement(name);
// createTest()根据 theClass与name(即方法名),为每个方法构造独立的TestCase的实例,指定TestCase的fName为name值,存储此TestCase于TestSuite
//就是说 :一个类有很多的需要测试方法,为每一个测试方法生成一个自身的实例,向上转型为TestCase,给TestCase的属性fName赋值为对应测试方法的名称
addTest(createTest(theClass, name));
}
5、准备执行测试
public TestResult doRun(Test suite, boolean wait) {
TestResult result= createTestResult(); //TestResult存储所有的执行结果信息
result.addListener(fPrinter); //添加监听器
long startTime= System.currentTimeMillis();
suite.run(result); //实际执行
long endTime= System.currentTimeMillis();
long runTime= endTime-startTime;
fPrinter.print(result, runTime);
return result;
}
6、开始执行
/**
* Runs the tests and collects their result in a TestResult.
*/
public void run(TestResult result) {
//遍历执行所有的测试
for (Enumeration e= tests(); e.hasMoreElements(); ) {
if (result.shouldStop() )
break;
Test test= (Test)e.nextElement();
runTest(test, result);
}
}
/**
* Runs the bare test sequence.
* @exception Throwable if any exception is thrown
*/
public void runBare() throws Throwable {
Throwable exception= null;
setUp(); //每个测试方法执行前执行的setUp()
try {
runTest(); //执行测试方法
} catch (Throwable running) {
exception= running;
}
finally {
try {
tearDown();//tearDown写在finally不论怎么样,在测试执行结束都会执行
} catch (Throwable tearingDown) {
if (exception == null) exception= tearingDown;
}
}
if (exception != null) throw exception;
}
7、通过反射执行实际的测试方法
/**
* Override to run the test and assert its state.
* @exception Throwable if any exception is thrown
*/
protected void runTest() throws Throwable {
assertNotNull(fName); // Some VMs crash when calling
Method runMethod= null;
try {
// use getMethod to get all public inherited
// methods. getDeclaredMethods returns all
// methods of this class but excludes the
// inherited ones.
//根据反射取得对应方法的Method类
runMethod= getClass().getMethod(fName, (Class[])null);
} catch (NoSuchMethodException e) {}
try {
//通过反射实际执行测试方法
runMethod.invoke(this, (Object[])new Class[0]);
}
catch (InvocationTargetException e) {}
}
8、实际的测试方法
public void testAdd() {
Arithmetic a = new Arithmetic();
int expected = 3;
assertEquals("失败", expected, a.add(1, 2));
}
9、执行Assert
/**
* Asserts that two ints are equal. If they are not
* an AssertionFailedError is thrown with the given message.
*/
static public void assertEquals(String message, int expected, int actual) {
assertEquals(message, new Integer(expected), new Integer(actual));
}
10、最终的错误的捕捉,以及测试结果打印。通过TestResult实现。
总结 :觉得和很多人说的那样,Junit更多体现的是优秀的设计思想。可惜自己现在还没有领悟到这步,只能简单的对整个的执行流程有初步的认识。继续努力。