Решением первой проблемы является перемещение логики в расширение 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
на фабричный шаблон, который выполняет внутренний подсчет ссылок, чтобы определить, является ли или не создавать / уничтожать ресурс.
Например (обратите внимание, что это грубо и может потребоваться некоторая настройка / обработка ошибок для устойчивости):
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, а отдельные тесты просто повторно используют уже созданный экземпляр (пересчет не позволяет ему быть фактически уничтоженным и воссозданным между тестами в наборе).
Почему бы не попробовать именованные каналы POSIX. Mac OSX - это операционная система в стиле POSIX, основанная на BSD, поэтому она должна быть прямой: