JUnit是由 Erich Gamma 和 Kent Beck 编写的一个回归测试框架,以Eclipse、IDEA等为代表的Java开拓情况都对JUnit提供了很是友善的支持。提到Erich Gamma,他就是台甫鼎鼎的
《设计模式:可复用面向工具软件的基本》
一书的作者之一。因此,JUnit傍边的设计模式的运用相当恰当,所以,JUnit的源码可谓相当优良的一本武林秘笈,很是值得一看。 本文基于JUnit4.12,将从JUnit的运行流程,Match验证,两个方面,来对JUnit的源码举办整体的阐明。
运行流程
JUnit的启动方法有许多,好比在Android Studio中我们可以直接点击某个被@Test注解的函数来运行:
此时,启动的是JUniteStarter,该类是intellij为我们提供的。感乐趣可以查察其源码: https://github.com/JetBrains/intellij-community/blob/master/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java
假如我们利用gradle, 可以执行gradle test
运行测试,实际上是在一个线程中执行SuiteTestClassProcessor的processTestClass要领来举办启动。其源码可以查察https://github.com/gradle/gradle/blob/master/subprojects/testing-base/src/main/java/org/gradle/api/internal/tasks/testing/SuiteTestClassProcessor.java
如上两种都是第三方东西为我们提供的便捷方法,实际上JUnit也提供了一个名为JUnitCore
的类来供我们利便的运行测试用例。
尽量启动JUnit的方法有许多,但这都是打开与JUnit对话的一些方法,最终执行的照旧JUnit傍边的起到焦点浸染的一些类,为了让各人对这些焦点boss有一个劈头相识,我画了一个类图:
劳务调派系统RunBefores" src="http://www.importnew.com/https:/blog.saymagic.cn/pic/understand-junit/o_1atjj1na31qbrjujamk2ku1na19.png" />
上图中仅是JUnit中的几个焦点的类,也是天职主要阐明的工具。这里先给出一些工具的职责,可以有个概略的相识,后头会通过代码就会更清楚每个工具是如何完成这些职责的:
getDescription()
返回了Description工具,记录着测试的信息。@RunWith(Suite.class)
标注的类需要利用Suite, 被@Ignore
标注的类需要利用IgnoreClassRunner。综上,我们先从ParentRunner看起,其结构函数如下:
protected ParentRunner(Class<?> testClass) throws InitializationError { this.testClass = createTestClass(testClass); validate(); }
this.testClass即前文所说的TestClass,我们进入createTestClass要领来查察其如何将class工具转换为TestClass。
protected TestClass createTestClass(Class<?> testClass) { return new TestClass(testClass); }
并没什么对象,详细的逻辑都写在TestClass的内部:
public TestClass(Class<?> clazz) { this.clazz = clazz; if (clazz != null && clazz.getConstructors().length > 1) { throw new IllegalArgumentException( "Test class can only have one constructor"); } Map<Class<? extends Annotation>, List<FrameworkMethod>> methodsForAnnotations = new LinkedHashMap<Class<? extends Annotation>, List<FrameworkMethod>>(); Map<Class<? extends Annotation>, List<FrameworkField>> fieldsForAnnotations = new LinkedHashMap<Class<? extends Annotation>, List<FrameworkField>>(); scanAnnotatedMembers(methodsForAnnotations, fieldsForAnnotations); this.methodsForAnnotations = makeDeeplyUnmodifiable(methodsForAnnotations); this.fieldsForAnnotations = makeDeeplyUnmodifiable(fieldsForAnnotations); }
可以看到,整个结构函数大抵都在做一些验证和初始化的事情,需要引起我们留意的应该是scanAnnotatedMembers要领:
protected void scanAnnotatedMembers(Map<Class<? extends Annotation>, List<FrameworkMethod>> methodsForAnnotations, Map<Class<? extends Annotation>, List<FrameworkField>> fieldsForAnnotations) { for (Class<?> eachClass : getSuperClasses(clazz)) { for (Method eachMethod : MethodSorter.getDeclaredMethods(eachClass)) { addToAnnotationLists(new FrameworkMethod(eachMethod), methodsForAnnotations); } // ensuring fields are sorted to make sure that entries are inserted // and read from fieldForAnnotations in a deterministic order for (Field eachField : getSortedDeclaredFields(eachClass)) { addToAnnotationLists(new FrameworkField(eachField), fieldsForAnnotations); } } }