Подтвердить что ты не робот

Spring Интеграционный тест медленный с Autowiring

Я пытаюсь ускорить тесты интеграции в нашей среде. Все наши классы проходят аутсорсинг. В нашем файле applicationContext.xml мы определили следующее:

<context:annotation-config/>
<context:component-scan base-package="com.mycompany.framework"/>
<context:component-scan base-package="com.mycompany.service"/>
...additional directories

Я заметил, что Spring сканирует все указанные выше каталоги и затем выполняет итерацию по каждому bean и кэширует свойства каждого из них. (Я просмотрел сообщения DEBUG от spring)

В результате следующий тест занимает около 14 секунд:

public class MyTest extends BaseSpringTest {
  @Test
  def void myTest(){
    println "test"
  }
}

Есть ли способ ленивой загрузки конфигурации? Я попытался добавить default-lazy-init="true", но это не сработало.

В идеале создается только beans, требуемое для теста.

заблаговременно.

Обновить. Я должен был сказать это раньше, я не хочу иметь файл контекста для каждого теста. Я также не думаю, что один контекстный файл только для тестов будет работать. (Этот тестовый контекстный файл в конечном итоге включит все)

4b9b3361

Ответ 1

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

Resource resource = new ClassPathResource(<PUT_XML_PATH_RIGHT_HERE>); // source.xml, for instance
InputStream in = resource.getInputStream();

Document document = new SAXReader().read(in);
Element root  = document.getRootElement();

/**
  * remove component-scanning
  */
for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
    Element element = (Element) i.next();

    if(element.getNamespacePrefix().equals("context") && element.getName().equals("component-scan"))
        root.remove(element);
}

in.close();

ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(true);
for (String source: new String[] {"com.mycompany.framework", "com.mycompany.service"}) {
    for (BeanDefinition bd: scanner.findCandidateComponents(source)) {
        root
        .addElement("bean")
        .addAttribute("class", bd.getBeanClassName());
    }
}

//add attribute default-lazy-init = true
root.addAttribute("default-lazy-init","true");

/**
  * creates a new xml file which will be used for testing
  */ 
XMLWriter output = new XMLWriter(new FileWriter(<SET_UP_DESTINATION_RIGHT_HERE>));
output.write(document);
output.close(); 

Кроме того, включите < context: annotation-config/ >

Как вам нужно выполнить описанную выше процедуру перед запуском любого теста, вы можете создать абстрактный класс, в котором вы можете запустить следующие

Настроить системное свойство Java для среды тестирования следующим образом

-Doptimized-application-context=false

и

public abstract class Initializer {

    @BeforeClass
    public static void setUpOptimizedApplicationContextFile() {
        if(System.getProperty("optimized-application-context").equals("false")) {
            // do as shown above

            // and

            System.setProperty("optimized-application-context", "true"); 
        }

    }

}

Теперь для каждого тестового класса просто расширяется Initializer

Ответ 2

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

В этом разделе обсуждается переопределение beans и пользовательский тестовый класс для этого:

Spring beans переопределить в среде unit test

Ответ 3

Это цена, которую вы платите за автоматическое обнаружение компонентов - это медленнее. Даже если ваш тест требует только определенного beans, ваш <context:component-scan> намного шире, и Spring будет создавать и инициализировать каждый найденный bean.

Я предлагаю вам использовать другой beans файл для ваших тестов, который определяет только beans, необходимый для самого теста, т.е. не использует <context:component-scan>.

Ответ 4

Вероятно, вам нужно реорганизовать вашу конфигурацию, чтобы использовать меньше автоустановки. Мой подход почти всегда связан с именем beans по имени, пытаясь быть явным с дизайном, но в то же время не слишком многословным, используя автосогласование, когда становится ясно, что вы используете его, чтобы скрыть мелкие детали.

Добавление: Если этого недостаточно, и вы используете junit, вы можете использовать утилиту из проекта JUnit Addons. Класс DirectorySuiteBuilder динамически создает тестовый набор из структуры каталогов. Таким образом, вы можете сделать что-то вроде

DirectorySuiteBuilder builder = new DirectorySuiteBuilder();
Test suite = builder.suite("project/tests");

Инициализируя контекст Spring перед этим кодом, вы можете запускать все тесты сразу. Однако, если каждый тест предполагает "чистый" Spring контекст, то вы, вероятно, потеряны.

Ответ 5

В такой ситуации вам нужно будет найти баланс. С одной стороны, вы бы очень хотели запустить тесты в кратчайшие сроки, чтобы быстро получить результаты. Это особенно важно при работе в командной среде с непрерывной интеграцией. С другой стороны, вы также справедливо хотели бы, чтобы конфигурация тестов была как можно более простой, поэтому обслуживание набора тестов не станет слишком громоздким, чтобы быть полезным.

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

Ответ 6

Конвенция bean factory предназначена для решения этой проблемы и значительно ускоряет весь процесс, 3 раза или более.

Ответ 7

Поскольку ни один из ответов здесь не решил эту проблему для меня, я добавляю свой собственный опыт.

Моя проблема заключалась в том, что Spring, Hibernate и EhCache сгруппированы в попытке утопить мою консоль с подробными сообщениями DEBUG, в результате чего нечитаемый журнал и - что намного хуже - невыносимая низкая производительность.

Конфигурирование уровней журналов исправлено:

Logger.getLogger("org.hibernate").setLevel(Level.INFO);
Logger.getLogger("net.sf.ehcache").setLevel(Level.INFO);
Logger.getLogger("org.springframework").setLevel(Level.INFO);