标签:
采用Junit4.8.2分析Junit实现架构
源码架构两个大包:junit包 org包
首先分析org.junit.runners.model包下的几个类
org.junit.runners.modela.TestClass
org.junit.runners.modela.FrameworkMethod
org.junit.runners.modela.FrameworkMember
org.junit.runners.modela.FrameworkField
涉及到的类:
org.junit.Assert;
org.junit.Before;
org.junit.BeforeClass;
org.junit.internal.runners.model.ReflectiveCallable;
org.junit.runners.BlockJUnit4ClassRunner;
package org.junit.runners.model;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
/**
* Wraps a class to be run, providing method validation and annotation searching
*/
public class TestClass
{
// 封装的单元测试类的Class对象
private final Class<?> fClass;
// 注解类型->对应的方法List
private Map<Class<?>, List<FrameworkMethod>> fMethodsForAnnotations = new HashMap<Class<?>, List<FrameworkMethod>>();
// 注解类型->对应的属性List
private Map<Class<?>, List<FrameworkField>> fFieldsForAnnotations = new HashMap<Class<?>, List<FrameworkField>>();
//创建一个TestClass对象(包裹着klass对象,即要测试的类对象),
//每次该构造方法执行,klass对象将被扫描类当中的注解annotations
//这个操作过程是十分昂贵的(希望将来JDK将会优化它),因此,请尽量共享TestClass的实例。
public TestClass(Class<?> klass)
{
fClass = klass;
if (klass != null && klass.getConstructors().length > 1)
throw new IllegalArgumentException("Test class can only have one constructor");
//遍历该类和其父类
for (Class<?> eachClass : getSuperClasses(fClass))
{
//扫描该方法的注解
for (Method eachMethod : eachClass.getDeclaredMethods())
addToAnnotationLists(new FrameworkMethod(eachMethod), fMethodsForAnnotations);
for (Field eachField : eachClass.getDeclaredFields())
addToAnnotationLists(new FrameworkField(eachField), fFieldsForAnnotations);
}
}
//将该方法或者给属性拥有的注解,全部加入映射
private <T extends FrameworkMember<T>> void addToAnnotationLists(T member, Map<Class<?>, List<T>> map)
{
//遍历该member上的annotation
for (Annotation each : member.getAnnotations())
{
Class<? extends Annotation> type = each.annotationType();
//获取该annotation的Type对应的List
List<T> members = getAnnotatedMembers(map, type);
//防止重复加入List (子类父类的情况,执行子类的)
if (member.isShadowedBy(members))
return;
//如果是Before或者BeforeClass注解,insert到第一个位置
if (runsTopToBottom(type))
members.add(0, member);
//其余(test,after,afterclass)insert到后面
else
members.add(member);
}
}
//返回跟annotationClass相同类型的Method集合
public List<FrameworkMethod> getAnnotatedMethods(Class<? extends Annotation> annotationClass)
{
return getAnnotatedMembers(fMethodsForAnnotations, annotationClass);
}
//返回跟annotationClass相同类型的Field集合
public List<FrameworkField> getAnnotatedFields(Class<? extends Annotation> annotationClass)
{
return getAnnotatedMembers(fFieldsForAnnotations, annotationClass);
}
//获取该annotation的Type对应的List
private <T> List<T> getAnnotatedMembers(Map<Class<?>, List<T>> map, Class<? extends Annotation> type)
{
if (!map.containsKey(type))
map.put(type, new ArrayList<T>());
return map.get(type);
}
//确保后加入的before放到前面
private boolean runsTopToBottom(Class<? extends Annotation> annotation)
{
return annotation.equals(Before.class) || annotation.equals(BeforeClass.class);
}
//将该类和父类所有Class对象放入List当中返回
private List<Class<?>> getSuperClasses(Class<?> testClass)
{
ArrayList<Class<?>> results = new ArrayList<Class<?>>();
Class<?> current = testClass;
while (current != null)
{
results.add(current);
current = current.getSuperclass();
}
return results;
}
/**
* Returns the underlying Java class.
*/
public Class<?> getJavaClass()
{
return fClass;
}
/**
* Returns the class‘s name.
*/
public String getName()
{
if (fClass == null)
return "null";
return fClass.getName();
}
/**
* Returns the only public constructor in the class, or throws an {@code
* AssertionError} if there are more or less than one.
*/
public Constructor<?> getOnlyConstructor()
{
Constructor<?>[] constructors = fClass.getConstructors();
Assert.assertEquals(1, constructors.length);
return constructors[0];
}
/**
* Returns the annotations on this class
*/
public Annotation[] getAnnotations()
{
if (fClass == null)
return new Annotation[0];
return fClass.getAnnotations();
}
public <T> List<T> getAnnotatedFieldValues(Object test, Class<? extends Annotation> annotationClass, Class<T> valueClass)
{
List<T> results = new ArrayList<T>();
for (FrameworkField each : getAnnotatedFields(annotationClass))
{
try
{
results.add(valueClass.cast(each.get(test)));
}
catch(IllegalAccessException e)
{
throw new RuntimeException("How did getFields return a field we couldn‘t access?");
}
}
return results;
}
}
下面是一个测试实例,通过使用TestClass类测试TestUnit的几个方法
package mytest.TestClass;
import java.util.List;
import org.junit.Test;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.TestClass;
/**
* org.junit.runners.model.FrameworkMethod 封装一个被测试的方法
*
* @Test 、@Before、@After、@BeforeClass、@AfterClass、@Ignore
*/
public class TestClassDemo
{
public static void test() throws Throwable
{
TestClass klass = new TestClass(TestUnit.class);
System.out.println(klass.getName());
List<FrameworkMethod> list = klass.getAnnotatedMethods(Test.class);
for (FrameworkMethod fm : list)
{
try
{
fm.invokeExplosively((TestUnit) klass.getJavaClass().newInstance(), new Object[0]);
}
catch(Throwable e)
{
System.out.println(e);
} finally
{
System.out.println(fm.getName() + " invoked!");
}
}
}
public static void main(String[] args) throws Throwable
{
TestClassDemo.test();
}
}
package mytest.TestClass;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class TestUnit
{
public TestUnit()
{
}
@Test
public void addx(int x)
{
assertEquals(5, 1 + x);
}
@Test
public void add()
{
assertEquals(5.0, 4.0, 0.1);
}
@Test
public void hello()
{
assertEquals(5.0, 4.0, 0.1);
}
}
输出结果是:
mytest.TestClass.TestUnit java.lang.IllegalArgumentException: wrong number of arguments addx invoked! java.lang.AssertionError: expected:<5.0> but was:<4.0> hello invoked! java.lang.AssertionError: expected:<5.0> but was:<4.0> add invoked!
标签:
原文地址:http://www.cnblogs.com/wuxinliulei/p/4933668.html