第一个问题的解决方案是通过 JUnit 4.9 中引入的 @ClassRule
将逻辑移动到连接到测试的扩展中:org.junit.rules.ExternalResource
public class MyTest {
@ClassRule
public static final TestResources res = new TestResources();
@Test
public void testFoo() {
// test logic here
}
}
public class TestResources extends ExternalResource {
protected void before() {
// Setup logic that used to be in @BeforeClass
}
protected void after() {
// Setup logic that used to be in @AfterClass
}
}
通过这种方式,以前由基类管理的资源将移出测试类层次结构,并移动到更模块化/可使用的“资源”中,这些资源可以在类运行之前创建,并在类运行后销毁。
至于同时解决这两个问题 - 即:将相同的高级设置/拆卸作为单个测试的一部分和套件的一部分运行 - 似乎没有任何特定的内置支持。但是...,您可以自己实现它:
只需将资源创建更改为工厂模式,该模式在内部引用计数以确定是否创建/销毁资源。@ClassRule
例如(请注意,这很粗糙,可能需要一些调整/错误处理才能实现稳健性):
public class TestResources extends ExternalResource {
private static int refCount = 0;
private static TestResources currentInstance;
public static TestResources getTestResources () {
if (refCount == 0) {
// currentInstance either hasn't been created yet, or after was called on it - create a new one
currentInstance = new TestResources();
}
return currentInstance;
}
private TestResources() {
System.out.println("TestResources construction");
// setup any instance vars
}
protected void before() {
System.out.println("TestResources before");
try {
if (refCount == 0) {
System.out.println("Do actual TestResources init");
}
}
finally {
refCount++;
}
}
protected void after() {
System.out.println("TestResources after");
refCount--;
if (refCount == 0) {
System.out.println("Do actual TestResources destroy");
}
}
}
您的套件/测试类都将资源用作通过工厂方法:@ClassResource
@RunWith(Suite.class)
@SuiteClasses({FooTest.class, BarTest.class})
public class MySuite {
@ClassRule
public static TestResources res = TestResources.getTestResources();
@BeforeClass
public static void suiteSetup() {
System.out.println("Suite setup");
}
@AfterClass
public static void suiteTeardown() {
System.out.println("Suite teardown");
}
}
public class FooTest {
@ClassRule
public static TestResources res = TestResources.getTestResources();
@Test
public void testFoo() {
System.out.println("testFoo");
}
}
public class BarTest {
@ClassRule
public static TestResources res = TestResources.getTestResources();
@Test
public void testBar() {
System.out.println("testBar");
}
}
当运行单个测试时,重新计数不会产生任何影响 - “实际初始化”和“实际拆解”只会发生一次。在套件中运行时,套件将创建TestResource,并且各个测试将仅重用已经实例化的测试(引用计数可防止它在套件中的测试之间被实际销毁和重新创建)。