JUnit4.8.2源代码中,最令yqj2065感兴趣的是org.junit.runner.Request,它是几个意思呢?
①封装JUnit的输入
JUnit4作为信息处理单元,它的输入是单元测试类——布满各种JUnit4的RUNTIME标注的类,但由于使用反射机制,JUnit4的输入严格地说是一个或多个(组)单元测试类的Class对象。早期版本的JUnit主要处理一个测试或测试构成的树,在增添了对过滤/
filtering和排序/ sorting支持后,JUnit4加入了这个概念。毕竟按照1.2.4 Java Annotation 提要的直接使用反射机制方式,代码会很复杂。
②知子莫若父??
面向对象中,一般父类不知其子类。然而在这里我们看见了反例。BlueJ中生成的JavaDoc
父类何时应该知道子类?这是一个问题,我只记得在WCF中遇到过数据契约中有个KnownType的东西。Request源代码中import其各个子类,并在一系列静态方法中使用它们而返回Request对象。Request是一个抽象类,通过静态方法返回Request(的子类) 的对象,这到底得和new有多大的仇恨啊。不过我喜欢。这些静态方法我不称其为静态工厂
public static Request aClass(Class<?> clazz)
public static Request classWithoutSuiteMethod(Class<?> clazz)
public static Request classes(Computer computer, Class<?>... classes)
public static Request classes(Class<?>...classes)
public static Request runner(final Runner runner)
public static Request method(Class<?> clazz, String methodName) {
Description method= Description.createTestDescription(clazz,methodName);
return Request.aClass(clazz).filterWith(method);
}
Request.method()将一个@Test封装为Request,毕竟@Test是基础。【HelloWorld 的单元测试类TestInJUnit4见源代码分析-1】
例程 8-3测试Request类 package myTest; import org.junit.runner.*; public class RequestDemo{ public static void test()throws Exception{ Request rqst = Request.method(TestInJUnit4.class,"add"); Result r = new JUnitCore().run(rqst); System.out.println(r.wasSuccessful() ); } }
③Request运用了工厂方法模式。
Request有一个工厂方法:public abstractRunner getRunner();
而且Request的设计有一个奇妙的地方:在创建对象的时候似乎使用装饰模式?Request为装饰模式中的Component、org.junit.internal.request.ClassRequest为具体组件,而FilterRequest和SortingRequest为具体装饰者(没有抽象Decorator)。而这一切,目的却是为了构建Request相关的Runner。
④Request使用set串接模式
Request的其他非静态方法filterWith、sortWith可以视为set方法。Request.method()中给出了例子:
return Request.aClass(clazz).filterWith(method);
Description
一个Request就搞得我昏头转向的,还是Description简单,它封装将要测试或已经测试的测试信息。使用组合模式,所有元素都是Composite对象。
有两个命名常量EMPTY(名字为"No Tests")和TEST_MECHANISM(名字为"Test mechanism")
作为叶子时,包含的atomic(a single test)信息有:
privatefinal String fDisplayName;// 本描述的显示名字(toString()的返回值)
privatefinal Annotation[] fAnnotations;// 一个测试的所有Annotation[]
相关的get方法:Collection<Annotation>getAnnotations()、StringgetDisplayName()、DescriptionchildlessCopy()、StringgetClassName()、StringgetMethodName()。
作为Composite时,维护一个ArrayList<Description>,有相关的方法:addChild(Description)、ArrayList<Description>getChildren()、isTest()(是否叶子)、isSuite()(是否组合)、isEmpty()。
Description的操作:int testCount()包含的叶子测试的总数。
Description有一个私有构造器,而提供了静态方法获得Description对象。
本文涉及的类型:Request及其3个子类,Description;涉及的设计模式:工厂方法模式、set串接模式、装饰模式、组合模式。
相关的类型:Runner、AllDefaultPossibilitiesBuilder、Filter等。