博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Junit 源码剖析(二)
阅读量:7068 次
发布时间:2019-06-28

本文共 11471 字,大约阅读时间需要 38 分钟。

junit4 下的所有的testcase都是在Runner下执行的, 可以将Runner理解为junit运行的容器, 默认情况下junit会使用JUnit4ClassRunner作为所有testcase的执行容器。

如果要定制自己的junit, 则可以实现自己的Runner,最简单的办法就是Junit4ClassRunner继承, spring-test, unitils这些框架就是采用这样的做法。

如在spring中是SpringJUnit4ClassRunner, 在unitils中是UnitilsJUnit4TestClassRunner, 一般我们的testcase都是在通过eclipse插件来执行的, eclipse的junit插件会在执行的时候会初始化指定的Runner。初始化的过程可以在ClassRequest中找到。

org.junit.internal.runners.Junit4ClassRunner

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 */@Deprecatedpublic class JUnit4ClassRunner extends Runner implements Filterable, Sortable{    private final List
fTestMethods; private TestClass fTestClass; //将要测试的TestCase实例Class对象传入 public JUnit4ClassRunner(Class
klass) throws InitializationError { fTestClass = new TestClass(klass); fTestMethods = getTestMethods(); //对要进行测试的方法展开验证 validate(); } //获取@test的方法List protected List
getTestMethods() { return fTestClass.getTestMethods(); } //对要进行测试的方法展开验证 protected void validate() throws InitializationError { MethodValidator methodValidator = new MethodValidator(fTestClass); methodValidator.validateMethodsForDefaultRunner(); methodValidator.assertValid(); } @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 = Description.createSuiteDescription(getName(), classAnnotations()); List
testMethods = fTestMethods; for (Method method : testMethods) spec.addChild(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, e.getCause()); 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) { notifier.fireTestStarted(description); notifier.fireTestFailure(new Failure(description, e)); notifier.fireTestFinished(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 (Iterator
iter = fTestMethods.iterator(); iter.hasNext();) { Method method = iter.next(); if (!filter.shouldRun(methodDescription(method))) iter.remove(); } if (fTestMethods.isEmpty()) throw new NoTestsRemainException(); } public void sort(final Sorter sorter) { Collections.sort(fTestMethods, new Comparator
() { public int compare(Method o1, Method o2) { return sorter.compare(methodDescription(o1), methodDescription(o2)); } }); } protected TestClass getTestClass() { return fTestClass; }}

  

org.junit.internal.runners.TestClass类

不同于上一节提到的org.junit.runners.model.TestClass类

 

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}. */@Deprecatedpublic class TestClass{    private final Class
fClass; public TestClass(Class
klass) { fClass = klass; } public List
getTestMethods() { return getAnnotatedMethods(Test.class); } List
getBefores() { return getAnnotatedMethods(BeforeClass.class); } List
getAfters() { return getAnnotatedMethods(AfterClass.class); } public List
getAnnotatedMethods(Class
annotationClass) { List
results = new ArrayList
(); for (Class
eachClass : getSuperClasses(fClass)) { Method[] methods = eachClass.getDeclaredMethods(); for (Method eachMethod : methods) { Annotation annotation = eachMethod.getAnnotation(annotationClass); if (annotation != null && !isShadowed(eachMethod, results)) results.add(eachMethod); } } if (runsTopToBottom(annotationClass)) Collections.reverse(results); return results; } private boolean runsTopToBottom(Class
annotation) { return annotation.equals(Before.class) || annotation.equals(BeforeClass.class); } private boolean isShadowed(Method method, List
results) { for (Method each : results) { if (isShadowed(method, each)) return true; } return false; } private boolean isShadowed(Method current, Method previous) { if (!previous.getName().equals(current.getName())) return false; if (previous.getParameterTypes().length != current.getParameterTypes().length) return false; for (int i = 0; i < previous.getParameterTypes().length; i++) { if (!previous.getParameterTypes()[i].equals(current.getParameterTypes()[i])) return false; } return true; } private List
> getSuperClasses(Class
testClass) { ArrayList
> results = new ArrayList
>(); Class
current = testClass; while (current != null) { results.add(current); current = current.getSuperclass(); } return results; } public Constructor
getConstructor() throws SecurityException, NoSuchMethodException { return fClass.getConstructor(); } public Class
getJavaClass() { return fClass; } public String getName() { return fClass.getName(); }}

  

org.junit.internal.runners.MethodValidator类

用于在org.junit.internal.runners.Junit4ClassRunner 类当中进行方法验证

 

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}. */@Deprecatedpublic class MethodValidator {	private final List
fErrors= new ArrayList
(); private TestClass fTestClass; //org.junit.internal.runners.JUnit4ClassRunner类中 //validate()方法中调用该构造函数-----第一步 public MethodValidator(TestClass testClass) { fTestClass = testClass; } public void validateInstanceMethods() { validateTestMethods(After.class, false); validateTestMethods(Before.class, false); validateTestMethods(Test.class, false); List
methods= fTestClass.getAnnotatedMethods(Test.class); if (methods.size() == 0) fErrors.add(new Exception("No runnable methods")); } public void validateStaticMethods() { validateTestMethods(BeforeClass.class, true); validateTestMethods(AfterClass.class, true); } //Junit4ClassRunner类中调用第二步 public List
validateMethodsForDefaultRunner() { //校验无参构造方法 validateNoArgConstructor(); //校验注解方法 validateStaticMethods(); validateInstanceMethods(); return fErrors; } //Junit4ClassRunner类中第三步 public void assertValid() throws InitializationError { if (!fErrors.isEmpty()) throw new InitializationError(fErrors); } public void validateNoArgConstructor() { try { fTestClass.getConstructor(); } catch (Exception e) { fErrors.add(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) { List
methods= fTestClass.getAnnotatedMethods(annotation); for (Method each : methods) { if (Modifier.isStatic(each.getModifiers()) != isStatic) { String state= isStatic ? "should" : "should not"; fErrors.add(new Exception("Method " + each.getName() + "() " + state + " be static")); } if (!Modifier.isPublic(each.getDeclaringClass().getModifiers())) fErrors.add(new Exception("Class " + each.getDeclaringClass().getName() + " should be public")); if (!Modifier.isPublic(each.getModifiers())) fErrors.add(new Exception("Method " + each.getName() + " should be public")); if (each.getReturnType() != Void.TYPE) fErrors.add(new Exception("Method " + each.getName() + " should be void")); if (each.getParameterTypes().length != 0) fErrors.add(new Exception("Method " + each.getName() + " should have no parameters")); } }}

  

  

 

转载于:https://www.cnblogs.com/wuxinliulei/p/4933851.html

你可能感兴趣的文章
linux提取指定列字符并打印所有内容(awk)
查看>>
减治算法求n个数中的最小数的位置
查看>>
css3学习 理论之文本
查看>>
Linux 安装python3.7.0
查看>>
<Linux命令行学习 第二节> CentOS - 远程登录管理工具
查看>>
[转]BEHAVOUR TREE2
查看>>
深入理解计算机操作系统(十)
查看>>
XML和Schema命名空间详解
查看>>
npm ERR! Unexpected end of JSON input while parsing near '...inimist":"^1.2.0"}
查看>>
Mybatis Generator逆向工程的使用
查看>>
设计模式(八)_门面模式
查看>>
BFS - 水题
查看>>
软件面试常见题目(转帖)
查看>>
[LeetCode] NO. 387 First Unique Character in a String
查看>>
理解管理信息系统
查看>>
UVA 11991 - Easy Problem from Rujia Liu?
查看>>
CF1101E Polycarp's New Job
查看>>
3d角色模型 制作 全过程 。3d max 。3d role model making process.3d Max
查看>>
开学第一周
查看>>
Pandas学习笔记,groupby的一些用法
查看>>