当前位置 > 主页 > APP资讯 > 技术资讯 >

关于Junit的 源码解析

日期:2019-09-19 14:51:02 作者:墨鱼 出自:贵州海鑫盛app开发公司



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


上一篇:关于Java里面Integer的源码 下一篇:关于php版微信开发如何接收消息,自动判断跟回复相应消息的方法
18585853123
在线留言