Как отложить вызов @PostConstruct до тех пор, пока jUnit не установит тестовый контекст

У меня есть статический компонент Spring 3.2.4 с защищенным методом @PostConstruct, который загружает данные из БД при инициализации.

При создании теста jUnit в моих тестовых методах я хотел бы настроить данные в БД для надлежащего тестирования bean-компонента. Однако, учитывая, что экземпляр bean-компонента создается до моих тестовых методов, я не знаю, как запросить Spring, чтобы отложить создание bean-компонента до завершения метода.

Учитывая, что метод @PostConstruct защищен, я не могу вызвать его напрямую для повторной инициализации bean-компонента, если я не использую отражение.

Есть ли другой способ сделать это или только отражение? Есть ли в Spring какие-либо классы Util, чтобы упростить задачу, или мне нужно использовать стандартное отражение Java?


person Eric B.    schedule 18.10.2013    source источник


Ответы (1)


Вы всегда можете запустить контекст программно для такого случая использования. Имейте в виду, что в этом случае вы отвечаете за жизненный цикл контекста. Следующий псевдокод иллюстрирует это:

@Test
public void yourTest() {
    // setup your database

    ConfigurableApplicationContext context =
        new ClassPathXmlApplicationContext("/org/foo/your-context.xml");
    // Or new AnnotationConfigApplicationContext(YourConfig.class)
    try {
        YourBean bean = context.getBean("beanId");
        // Assertions
    } finally {
        context.close();
    }
}

Вероятно, вам понадобится Spring для инициализации вашей базы данных. Например, вы можете использовать стандартную поддержку контекста теста Spring для инициализации только компонентов, необходимых для настройки базы данных, и программно запустить другой контекст для утверждения вашей службы. Если этому контексту нужны какие-то службы, которые использовались для инициализации базы данных, вы можете вместо этого запустить дочерний контекст, например

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration // for instance FooTest-context.xml
public class FooTest {

    @Autowired
    private ApplicationContext mainContext;

    @Test
    public void yourTest() {
        // setup your database

        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext();
        context.setParent(mainContext);
        context.setConfigLocation("/org/foo/your-context.xml");
        context.refresh();
        try {
            YourBean bean = context.getBean("beanId");
            // Assertions
        } finally {
            context.close();
        }
    }
}

Если это становится повторяющимся вариантом использования, вы можете создать шаблонный метод, который запускает контейнер и вызывает интерфейс обратного вызова. Таким образом, вы можете централизованно совместно использовать управление жизненным циклом контекста.

person Stephane Nicoll    schedule 13.03.2014
comment
Спасибо. В итоге я решил решить проблему, но ваше решение определенно дает мне другой способ взглянуть на нее. - person Eric B.; 13.03.2014