Spring интеграционные тесты с профилем

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

Использование профилей Spring bean очень хорошо работает для изменения среды веб-приложения.

Проблема заключается в том, что нам необходимо изменить код интеграции для среды. В этих случаях интеграционный тест загружает контекст приложения веб-приложения. Таким образом, нам не нужно переопределять соединения с базой данных, константы и т.д. (Применяя принцип DRY).

Мы устанавливаем наши интеграционные тесты следующим образом.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = ["classpath:applicationContext.xml"])
public class MyTestIT
{
   @Autowired
   @Qualifier("myRemoteURL")  // a value from the web-app applicationContext.xml
   private String remoteURL;
   ...
 }

Я могу запустить его локально с помощью @ActiveProfiles, но это жестко закодировано и приводит к сбою наших тестов на сервере сборки.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = ["classpath:applicationContext.xml"])
@ActiveProfiles("development")
public class MyTestIT
{ ... }

Я также попытался использовать @WebAppConfiguration, надеясь, что он каким-то образом может импортировать свойство spring.profiles.active из Maven, но это не работает.

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

Ответы

Ответ 1

Как уже указывали другие люди, вы можете использовать Maven для установки системного свойства spring.profiles.active, не допуская использования @ActiveProfiles, но это не удобно для тестов, выполняемых в среде IDE.

Для программных средств для установки активных профилей у вас есть несколько вариантов.

  • Spring 3.1: напишите пользовательский ContextLoader, который подготавливает контекст, задав активные профили в контексте Environment.
  • Spring 3.2: пользовательский ContextLoader остается опцией, но лучше выбрать ApplicationContextInitializer и настроить его с помощью атрибута initializers @ContextConfiguration. Пользовательский инициализатор может настроить Environment путем программной настройки активных профилей.
  • Spring 4.0: вышеупомянутые варианты все еще существуют; однако с Spring Framework 4.0 для этой цели существует специальный выделенный ActiveProfilesResolver API: программно определить набор активных профилей для использования в тесте. ActiveProfilesResolver можно зарегистрировать с помощью атрибута resolver @ActiveProfiles.

Привет,

Сэм (автор Spring TestContext Framework)

Ответ 2

У меня была аналогичная проблема: я хотел запустить все свои тесты интеграции с профилем по умолчанию, но разрешить пользователю переопределять профиль, представляющий другую среду или даже вкус db, без изменения значения @ActiveProfiles. Это можно сделать, если вы используете Spring 4.1+ с помощью специального ActiveProfilesResolver.

В этом примере resolver ищет системное свойство spring.profiles.active, и если он не существует, он будет делегировать значение по умолчанию, которое просто использует аннотацию @ActiveProfiles.

public class SystemPropertyActiveProfileResolver implements ActiveProfilesResolver {

private final DefaultActiveProfilesResolver defaultActiveProfilesResolver = new DefaultActiveProfilesResolver();

@Override
public String[] resolve(Class<?> testClass) {

    if(System.getProperties().containsKey("spring.profiles.active")) {

        final String profiles = System.getProperty("spring.profiles.active");
        return profiles.split("\\s*,\\s*");

    } else {

        return defaultActiveProfilesResolver.resolve(testClass);
    }
}

}

И в ваших тестовых классах вы будете использовать его следующим образом:

@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles( profiles={"h2","xyz"},
resolver=SystemPropertyActiveProfileResolver.class)
public class MyTest { }

Конечно, вы можете использовать другие методы, кроме проверки наличия системного свойства для установки активных профилей. Надеюсь, это поможет кому-то.

Ответ 3

Если вы хотите избежать жесткого кодирования профиля, вы можете использовать системное свойство spring.profiles.active и установить его на все, что вы необходимости в этой конкретной среде, например у нас есть профили "dev", "stage" и "prod" для разных условий; также у нас есть тестовые, тестовые и тестовые серверы для тестирования.

Помните, что вы можете иметь более одного профиля в этом системном свойстве, используя список разделенных запятыми значений, например. "Тест, тест-контроль качества".

Вы можете указать системные свойства в проекте maven в плагине maven surefire или передать их следующим образом:

mvn -DargLine="-DpropertyName=propertyValue"

Ответ 4

Как отметил @ElderMael, вы можете использовать свойство argLine плагина maven surefire. Часто, когда мне нужно запустить все тесты с различными конкретными профилями Spring, я определяю дополнительный профиль maven. Пример:

<profiles>
    <profile>
        <id>foo</id>
        <dependencies>
            <!-- additional dependencies if needed, i.e. database drivers ->
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <argLine>-Dspring.profiles.active=foo</argLine>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

С помощью этого подхода вы можете легко запустить весь тест с активированным профилем командой maven:

mvn clean test -Pfoo

Аннотация @ActiveProfile хороша, но иногда нам нужно запустить весь тест с активированными конкретными профилями и с жестко закодированными параметрами @ActiveProfile, это проблема.

Например: по умолчанию интеграционный тест с H2 in-db памяти, но иногда вы хотите запустить тест в "реальной" базе данных. Вы можете определить этот дополнительный профиль maven и определить работу Jenkins. С SpringBoot вы также можете добавить дополнительные свойства для проверки/ресурсов с помощью имени application-foo.yml(или свойств), и эти свойства будут учтены.

Ответ 5

есть много лиц для этой проблемы. в моем случае, простое дополнение к build.gradle уже помогло:

test { systemProperties = System.properties }