
junit4 下的所有的testcase都是在Runner下执行的, 可以将Runner理解为junit运行的容器, 默认情况下junit会使用JUnit4ClassRunner作为所有testcase的执行容器。
如果要定制自己的junit, 则可以实现自己的Runner,最简单的办法就是Junit4ClassRunner继承, spring-test, unitils这些框架就是采用这样的做法。
如在spring中是SpringJUnit4ClassRunner, 在unitils中是UnitilsJUnit4TestClassRunner, 一般我们的testcase都是在通过eclipse插件来执行的, eclipse的junit插件会在执行的时候会初始化指定的Runner。初始化的过程可以在ClassRequest中找到。
package org.junit.internal.runners;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.manipulation.Filter;
import org.junit.runner.manipulation.Filterable;
import org.junit.runner.manipulation.NoTestsRemainException;
import org.junit.runner.manipulation.Sortable;
import org.junit.runner.manipulation.Sorter;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
/**
* @deprecated Included for backwards compatibility with JUnit 4.4. Will be
* removed in the next release. Please use
* {@link BlockJUnit4ClassRunner} in place of
* {@link JUnit4ClassRunner}.
*
* This may disappear as soon as 1 April 2009
*/
@Deprecated
public class JUnit4ClassRunner extends Runner implements Filterable, Sortable
{
private final ListfTestMethods;
private TestClass fTestClass;
//将要测试的TestCase实例Class对象传入
public JUnit4ClassRunner(Class klass) throws InitializationError
{
fTestClass = new TestClass(klass);
fTestMethods = getTestMethods();
//对要进行测试的方法展开验证
validate();
}
//获取@test的方法List
protected ListgetTestMethods()
{
return fTestClass.getTestMethods();
}
//对要进行测试的方法展开验证
protected void validate() throws InitializationError
{
MethodValidator methodValidator = new MethodValidator(fTestClass);
();
();
}
@Override
public void run(final RunNotifier notifier)
{
new ClassRoadie(notifier, fTestClass, getDescription(), new Runnable()
{
public void run()
{
runMethods(notifier);
}
}).runProtected();
}
protected void runMethods(final RunNotifier notifier)
{
for (Method method : fTestMethods)
invokeTestMethod(method, notifier);
}
@Override
public Description getDescription()
{
Description spec = (getName(), classAnnotations());
ListtestMethods = fTestMethods;
for (Method method : testMethods)
(methodDescription(method));
return spec;
}
protected Annotation[] classAnnotations()
{
return fTestClass.getJavaClass().getAnnotations();
}
protected String getName()
{
return getTestClass().getName();
}
protected Object createTest() throws Exception
{
return getTestClass().getConstructor().newInstance();
}
protected void invokeTestMethod(Method method, RunNotifier notifier)
{
Description description = methodDescription(method);
Object test;
try
{
test = createTest();
}
catch(InvocationTargetException e)
{
testAborted(notifier, description, ());
return;
}
catch(Exception e)
{
testAborted(notifier, description, e);
return;
}
TestMethod testMethod = wrapMethod(method);
new MethodRoadie(test, testMethod, notifier, description).run();
}
private void testAborted(RunNotifier notifier, Description description, Throwable e)
{
(description);
(new Failure(description, e));
(description);
}
protected TestMethod wrapMethod(Method method)
{
return new TestMethod(method, fTestClass);
}
protected String testName(Method method)
{
return method.getName();
}
protected Description methodDescription(Method method)
{
return Description.createTestDescription(getTestClass().getJavaClass(), testName(method), testAnnotations(method));
}
protected Annotation[] testAnnotations(Method method)
{
return method.getAnnotations();
}
public void filter(Filter filter) throws NoTestsRemainException
{
for (Iteratoriter = (); ();)
{
Method method = ();
if (!(methodDescription(method)))
();
}
if (())
throw new NoTestsRemainException();
}
public void sort(final Sorter sorter)
{
(fTestMethods, new Comparator()
{
public int compare(Method o1, Method o2)
{
return sorter.compare(methodDescription(o1), methodDescription(o2));
}
});
}
protected TestClass getTestClass()
{
return fTestClass;
}
}类
不同于上一节提到的类
package org.junit.internal.runners;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runners.BlockJUnit4ClassRunner;
/**
* @deprecated Included for backwards compatibility with JUnit 4.4. Will be
* removed in the next release. Please use
* {@link BlockJUnit4ClassRunner} in place of
* {@link JUnit4ClassRunner}.
*/
@Deprecated
public class TestClass
{
private final Class fClass;
public TestClass(Class klass)
{
fClass = klass;
}
public ListgetTestMethods()
{
return getAnnotatedMethods();
}
ListgetBefores()
{
return getAnnotatedMethods();
}
ListgetAfters()
{
return getAnnotatedMethods();
}
public ListgetAnnotatedMethods(Class annotationClass)
{
Listresults = new ArrayList();
for (Class eachClass : getSuperClasses(fClass))
{
Method[] methods = ();
for (Method eachMethod : methods)
{
Annotation annotation = (annotationClass);
if (annotation != null && !isShadowed(eachMethod, results))
(eachMethod);
}
}
if (runsTopToBottom(annotationClass))
(results);
return results;
}
private boolean runsTopToBottom(Class annotation)
{
return () || ();
}
private boolean isShadowed(Method method, Listresults)
{
for (Method each : results)
{
if (isShadowed(method, each))
return true;
}
return false;
}
private boolean isShadowed(Method current, Method previous)
{
if (!().equals(()))
return false;
if (().length != ().length)
return false;
for (int i = 0; i < ().length; i++)
{
if (!()[i].equals(()[i]))
return false;
}
return true;
}
private List<Class> getSuperClasses(Class testClass)
{
ArrayList<Class> results = new ArrayList<Class>();
Class current = testClass;
while (current != null)
{
(current);
current = ();
}
return results;
}
public Constructor getConstructor() throws SecurityException, NoSuchMethodException
{
return fClass.getConstructor();
}
public Class getJavaClass()
{
return fClass;
}
public String getName()
{
return fClass.getName();
}
}类
用于在 类当中进行方法验证
package org.junit.internal.runners;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runners.BlockJUnit4ClassRunner;
/**
* @deprecated Included for backwards compatibility with JUnit 4.4. Will be
* removed in the next release. Please use
* {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}.
*/
@Deprecated
public class MethodValidator {
private final ListfErrors= new ArrayList();
private TestClass fTestClass;
//类中
//validate()方法中调用该构造函数-----第一步
public MethodValidator(TestClass testClass) {
fTestClass = testClass;
}
public void validateInstanceMethods() {
validateTestMethods(After.class, false);
validateTestMethods(, false);
validateTestMethods(, false);
Listmethods= ();
if (() == 0)
(new Exception("No runnable methods"));
}
public void validateStaticMethods() {
validateTestMethods(, true);
validateTestMethods(, true);
}
//Junit4ClassRunner类中调用第二步
public ListvalidateMethodsForDefaultRunner() {
//校验无参构造方法
validateNoArgConstructor();
//校验注解方法
validateStaticMethods();
validateInstanceMethods();
return fErrors;
}
//Junit4ClassRunner类中第三步
public void assertValid() throws InitializationError {
if (!())
throw new InitializationError(fErrors);
}
public void validateNoArgConstructor() {
try {
();
} catch (Exception e) {
(new Exception("Test class should have public zero-argument constructor", e));
}
}
//校验要测试的方法 是否静态方法、是否public方法、是否返回值void、是否无参数
//@param annotation 要测试的annotation类
//@param isStatic 是否要求静态方法
private void validateTestMethods(Class annotation,boolean isStatic) {
Listmethods= (annotation);
for (Method each : methods) {
if ((()) != isStatic) {
String state= isStatic ? "should" : "should not";
(new Exception("Method " + () + "() "
+ state + " be static"));
}
if (!(().getModifiers()))
(new Exception("Class " + ().getName()
+ " should be public"));
if (!(()))
(new Exception("Method " + ()
+ " should be public"));
if (() != )
(new Exception("Method " + ()
+ " should be void"));
if (().length != 0)
(new Exception("Method " + ()
+ " should have no parameters"));
}
}
}