首页 > 代码库 > 【JUnit4.10源代码分析】3.4 Description与测试树
【JUnit4.10源代码分析】3.4 Description与测试树
Description使用组合模式描述一个测试树。组合模式中所有元素都是Composite对象。
Description有成员变量private final ArrayList<Description>fChildren= newArrayList<Description>(); //无元素
保存其子结点。fChildren非空,所以任何子结点都是一个Composite,但是this. getChildren().size()为0的结点,事实上就是叶子。
测试树
一颗测试树Description,有诸多Description构成。每一个Description包含的数据:
privatefinal ArrayList<Description> fChildren= newArrayList<Description>(); //无元素
privatefinal String fDisplayName;
privatefinal Annotation[] fAnnotations;
叶子结点有:一个被测试的方法(atomic/ a single test),Description类中定义的的两个命名常量EMPTY(名字为"No Tests")和TEST_MECHANISM(名字为"Test mechanism")一般元素/Composite,重点是fChildren的构造。一个单元测试类,其Description的子结点包括所有@test修饰的方法(不包括@Before等修饰的方法);一个成组测试类的子结点包括几个单元测试类。例如有Unit1、Unit2、Unit3,而SuiteUnit将Unit2、Unit3组成一组。
package units; import static tool.Print.*; import org.junit.*;//各种标注 public class Unit1{ public Unit1() { } @Before public void setUp(){ } @After public void tearDown(){ } @Test public void m1(){ pln("Unit1.m1()"); } @Test @Ignore public void m2(){ pln("Unit1.m2()"); } @Test public void m3(){ pln("Unit1.m3()"); } }
package units; public class Unit2 { @org.junit.Test public void test2() { System.out.println("Unit2.test2()"); } } package units; public class Unit3 { @org.junit.Test public void testSth() {<span style="white-space:pre"> </span> System.out.println("Unit3.testSth()"); } }SuiteUnit 的代码:
package units; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ Unit2.class, Unit3.class, }) public class SuiteUnit {}先看一个例子,打印测试 Request.classes(Unit1.class,SuiteUnit.class)时的测试树。
package demo; import static tool.Print.*; import units.Unit1; import units.SuiteUnit; import org.junit.runner.Description; import org.junit.runner.Request; import org.junit.runner.Runner; import java.util.regex.Matcher; import java.util.regex.Pattern; /** *测试Description的各种用法 * @author yqj2065 */ public class DescriptionDemo { public static void tree(){ Request rqst = Request.classes(Unit1.class,SuiteUnit.class); Runner r=rqst.getRunner(); Description descr = r.getDescription(); String prefix = ""; print(descr,prefix); pln( "the total number of atomic tests = "+descr.testCount() );//the total number of atomic tests. }
public static void print(Description now,String prefix){ pln(prefix+ now.getDisplayName() ); if(now.isSuite()) { prefix+=" "; for (Description x : now.getChildren()){ print(x,prefix); } } } public static void main(String... args) { tree(); } }
输出:
null
units.Unit1
m1(units.Unit1)
m2(units.Unit1)
m3(units.Unit1)
units.SuiteUnit
units.Unit2
test2(units.Unit2)
units.Unit3
testSth(units.Unit3)
the total number of atomic tests = 5
此时的测试树有两个子结点:单元测试类units.Unit1(的Description)和成组测试类units.SuiteUnit。单元测试类的子结点都是叶子;而units.SuiteUnit的子结点为包含的单元测试类。
相关方法
String getDisplayName():返回fDisplayName。本描述的用于打印的名字,一般情况下都采用类全名或JUnit的方法字符串如method(所属类的全名)String getClassName()、String getMethodName():解析方法字符串,获得@Test修饰的方法相关的类全名和方法名;Class<?> getTestClass(),由getClassName()的返回值为参数name调用Class.forName(name);
ArrayList<Description> getChildren():返回fChildren。
void addChild(Description description)
isTest()(是否叶子)、isSuite()(是否组合):互斥的一对判断
isEmpty()
Collection<Annotation> getAnnotations():将fAnnotations数组形式的转换为Collection;本Description所对应元素前使用的标注;
<T extends Annotation> T getAnnotation(Class<T> annotationType)。fAnnotations中是否含有annotationType。
@Override hashCode()、equals(Object obj)、toString();
组合模式中的Operation()的对应物为int testCount(),包含的叶子测试的总数。
构造器
Description有一个私有构造器,禁止客户类直接创建Description。
private Description(final String displayName, Annotation... annotations) {
fDisplayName= displayName;
fAnnotations= annotations;
}
然而,Description的构造,它提供了静态方法获得Description对象。这些静态方法构造本Description的基本信息,不添加子结点。因而4个静态方法都是调用私有构造器,
public static Description createSuiteDescription(String name, Annotation... annotations)
public static Description createSuiteDescription(Class<?> testClass)
public static Description createTestDescription(Class<?> clazz, String name, Annotation... annotations) {
return new Description(String.format("%s(%s)", name, clazz.getName()), annotations);
}
public static Description createTestDescription(Class<?> clazz, String name) {
return createTestDescription(clazz, name, new Annotation[0]);
}
其中String str = String.format("%s(%s)", "m1", "Class1");
str为m1(Class1),JUnit的方法字符串如method(所属类的全名)
DescriptionDemo中测试树是如何构建的呢?ParentRunner<T>的代码
@Override public Description getDescription() { Description description= Description.createSuiteDescription(getName(), getRunnerAnnotations()); for (T child : getFilteredChildren()) description.addChild(describeChild(child)); return description; }可以通过“调试文件”,跟踪查看。
【JUnit4.10源代码分析】3.4 Description与测试树