Запуск одного теста из набора с @ClassRule завершается неудачно - PullRequest
0 голосов
/ 28 сентября 2018

Чтобы создать среду только один раз и избежать наследования, я определил класс JUnit Suite с помощью @ClassRule:

@RunWith(Suite.class)               
@Suite.SuiteClasses({               
  SuiteTest1.class              
})      

public class JUnitTest {

    @ClassRule
    private static DockerComposeContainer env = ...


    @BeforeClass
    public static void init(){
        ...
    }

    ...

}

И есть класс Test, который использует env в методе test:

public class SuiteTest1 {               

    @Test
    public void method(){
        client.query(...);// Executes a query against docker container


    }
}

Когда я выполняю тесты с помощью Test Suite, все работает как положено.Но когда я напрямую пытаюсь запустить (даже с IDE) тестовый класс SuiteTest1, он не работает и ничего из Suite не вызывается (т. Е. @ ClassRule и @BeforeClass).

Есть ли какие-либо предложения о том, как добиться хорошего одиночного выполнения SuiteTest1 (без вызова статических методов JUnitTest из SuiteTest1)?

1 Ответ

0 голосов
/ 15 ноября 2018

Перефразируя вопрос: вам нужен пакет JUnit с перехватчиками «все-все» и «все-таки», которые также запускались бы при выполнении тестов один за другим (например, из IDE).

AFAIK JUnit 4 предоставляетничего из этого не готово, но если вы согласны с включением некоторых сторонних программ Spring ( spring-test и spring-context ) в ваш проект, ямогу предложить обходной путь, который я использовал.

Полный пример того, что описано в этом вопросе , можно найти здесь .

Решение(с использованием Spring)

Мы будем использовать контекст Spring для реализации нашей инициализации и очистки.Давайте добавим базовый класс для наших тестов:

@ContextConfiguration(initializers = AbstractTestClass.ContextInitializer.class)
public class AbstractTestClass {

    @ClassRule
    public final static SpringClassRule springClassRule = new SpringClassRule();

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();

    public static class ContextInitializer
            implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext context) {
            System.out.println("Initializing context");

            context.addApplicationListener(
                    (ApplicationListener<ContextClosedEvent>)
                            contextClosedEvent ->
                                    System.out.println("Closing context"));
        }
    }
}

Обратите внимание на правила SpringClassRule и SpringMethodRule JUnit, которые расширяют наш базовый класс с помощью Spring-superpowers(Обработка аннотации пружинного теста - в данном случае ContextConfiguration, но здесь есть еще много полезного - подробности см. Ссылка на весеннее тестирование ).Вы можете использовать SpringRunner для этой цели, но это гораздо менее гибкое решение (поэтому оно опущено).

Тестовые классы:

public class TestClass1 extends AbstractTestClass {

    @Test
    public void test() {
        System.out.println("TestClass1 test");
    }
}

public class TestClass2 extends AbstractTestClass {

    @Test
    public void test() {
        System.out.println("TestClass2 test");
    }
}

И набор тестов:

@RunWith(Suite.class)
@SuiteClasses({TestClass1.class, TestClass2.class})
public class TestSuite {
}

Вывод при запуске пакета (удалены краткие журналы, относящиеся к Spring):

Initializing context
TestClass1 test
TestClass2 test
Closing context

Вывод при запуске одного теста (TestClass1):

Initializing context
TestClass1 test
Closing context

Слово объяснения

Способ работает из-за кеширования контекста Spring.Цитата из документов:

После того, как платформа TestContext загрузит ApplicationContext (или WebApplicationContext) для теста, этот контекст кэшируется и повторно используется для всех последующих тестов, которые объявляют ту же уникальную конфигурацию контекстав том же тестовом наборе.Чтобы понять, как работает кэширование, важно понять, что подразумевается под «уникальным» и «набором тестов».

- https://docs.spring.io/spring/docs/5.1.2.RELEASE/spring-framework-reference/testing.html#testcontext-ctx-management-caching

Остерегайтесь того, что вы получите другоеконтекст (и другая инициализация), если вы переопределяете конфигурацию контекста (например, добавляете другой инициализатор контекста с ContextConfiguration) для любого из классов в иерархии (TestClass1 или TestClass2 в нашем примере).

Использование бобов для совместного использования экземпляров

Вы можете определить бины в своем контексте.Они будут доступны для всех тестов в одном контексте.Это может быть полезно для совместного использования объекта в наборе тестов (контейнер Testcontainers в вашем случае, судя по тегам).

Давайте добавим bean-компонент:

@ContextConfiguration(initializers = AbstractTestClass.ContextInitializer.class)
public class AbstractTestClass {

    @ClassRule
    public final static SpringClassRule springClassRule = new SpringClassRule();

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();

    public static class ContextInitializer
            implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext context) {
            ADockerContainer aDockerContainer = new ADockerContainer();
            aDockerContainer.start();

            context.getBeanFactory().registerResolvableDependency(
                    ADockerContainer.class, aDockerContainer);

            context.addApplicationListener(
                    (ApplicationListener<ContextClosedEvent>)
                            contextClosedEvent ->
                                    aDockerContainer.stop());
        }
    }
}

и добавим его вклассы теста:

public class TestClass1 extends AbstractTestClass {

    @Autowired
    private ADockerContainer aDockerContainer;

    @Test
    public void test() {
        System.out.println("TestClass1 test " + aDockerContainer.getData());
    }
}

public class TestClass2 extends AbstractTestClass {

    @Autowired
    private ADockerContainer aDockerContainer;

    @Test
    public void test() {
        System.out.println("TestClass2 test " + aDockerContainer.getData());
    }
}

ADockerContainer класс:

public class ADockerContainer {
    private UUID data;

    public void start() {
        System.out.println("Start container");
        data = UUID.randomUUID();
    }

    public void stop() {
        System.out.println("Stop container");
    }

    public String getData() {
        return data.toString();
    }
}

(Пример) вывод:

Start container
TestClass1 test 56ead80b-ec34-4dd6-9c0d-d6f07a4eb0d8
TestClass2 test 56ead80b-ec34-4dd6-9c0d-d6f07a4eb0d8
Stop container
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...