Ответ 1
Решение первой проблемы состоит в том, чтобы переместить логику в расширение org.junit.rules.ExternalResource
, подключенного к тесту, с помощью @ClassRule
, введенный в JUnit 4.9:
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
на шаблон factory, который внутренне ссылается на подсчет, чтобы определить, создавать или уничтожать ресурс.
Например (обратите внимание, что это грубо и может потребоваться некоторая настройка/обработка ошибок для обеспечения надежности):
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
через метод factory:
@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");
}
}
При запуске отдельного теста пересчет не будет иметь никакого эффекта - "фактический init" и "фактическое отключение" произойдет только один раз. При запуске через пакет пакет будет создавать TestResource, и отдельные тесты будут просто повторно использовать уже созданный (refcounting не позволяет ему фактически уничтожаться и воссоздаваться между тестами в пакете).