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