经过深思熟虑和一些死胡同,我开始使用以下模式:
在下面的:
- [INTERFACE] 指被测试的接口。
- [CLASS] 是指被测试接口的实现。
构建接口测试,以便开发人员可以测试实现是否符合接口和随附文档中规定的合同。
被测试的主要项目使用 [INTERFACE]ProducerInterface 的实例来创建被测试对象的实例。[INTERFACE]ProducerInterface 的实现必须跟踪测试期间创建的所有实例,并在请求时关闭所有实例。有一个 Abstract[INTERFACE]Producer 可以处理大部分功能,但需要 createNewINTERFACE 实现。
测试
接口测试被标记为 Abstract[INTERFACE]Test。测试通常扩展 Abstract[INTERFACE]ProducerUser 类。此类处理在测试结束时清理所有图表,并为实现者提供一个挂钩以插入他们的 [INTERFACE]ProducerInterface 实现。
一般来说,实现一个测试需要几行代码,如下例所示,新的 Foo 图实现正在测试中。
public class FooGraphTest extends AbstractGraphTest {
// the graph producer to use while running
GraphProducerInterface graphProducer = new FooGraphTest.GraphProducer();
@Override
protected GraphProducerInterface getGraphProducer() {
return graphProducer;
}
// the implementation of the graph producer.
public static class GraphProducer extends AbstractGraphProducer {
@Override
protected Graph createNewGraph() {
return new FooGraph();
}
}
}
套房
测试套件被命名为 Abstract[INTERFACE]Suite。套件包含几个测试,用于对被测对象的组件进行所有测试。例如,如果 Foo.getBar() 返回 Bar 接口的实例,则 Foo 套件包括对 Foo 本身的测试以及运行 Bar 测试 Bar。运行套件比运行测试要复杂一些。
套件是使用 JUnit 4 @RunWith(Suite.class) 和 @Suite.SuiteClasses({ }) 注释创建的。这有几个开发人员应该知道的影响:
- 套件类在运行期间不会被实例化。
- 测试类名称必须在编码时(而不是运行时)已知,因为它们在注释中列出。
- 测试的配置必须在类加载的静态初始化阶段进行。
为了满足这些要求,Abstract[INTERFACE]Suite 有一个静态变量来保存 [INTERFACE]ProducerInterface 的实例和一些抽象测试的本地静态实现,这些实现通过返回“get[INTERFACE]Producer()”方法静态实例。然后在 @Suite.SuiteClasses 注释中使用本地测试的名称。这使得为 [INTERFACE] 实现创建 Abstract[INTERFACE]Suite 的实例相当简单,如下所述。
public class FooGraphSuite extends AbstractGraphSuite {
@BeforeClass
public static void beforeClass() {
setGraphProducer(new GraphProducer());
}
public static class GraphProducer extends AbstractGraphProducer {
@Override
protected Graph createNewGraph() {
return new FooGraph();
}
}
}
注意 beforeClass() 方法是用@BeforeClass 注释的。@BeforeClass 导致它在类中的任何测试方法之前运行一次。这将在套件运行之前设置图形生成器的静态实例,以便将其提供给随附的测试。
未来
我希望通过使用 java 泛型可以实现进一步的简化和删除重复代码,但我还没有达到这一点。