Java 带有配置文件的 Spring 集成测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20551681/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:44:43  来源:igfitidea点击:

Spring integration tests with profile

javaspringspring-mvcspring-test

提问by David V

In our Spring web applications, we use the Spring bean profiles to differentiate three scenarios: development, integration, and production. We use them to connect to different databases or set other constants.

在我们的 Spring Web 应用程序中,我们使用 Spring bean 配置文件来区分三个场景:开发、集成和生产。我们使用它们来连接不同的数据库或设置其他常量。

Using Spring bean profiles works very well for the changing the web app environment.

使用 Spring bean 配置文件非常适合更改 Web 应用程序环境。

The problem we have is when our integration test codeneeds change for the environment. In these cases, the integration test loads the application context of the web app. This way we don't have to redefine database connections, constants, etc. (applying the DRY principle).

我们遇到的问题是我们的集成测试代码何时需要针对环境进行更改。在这些情况下,集成测试加载 Web 应用程序的应用程序上下文。这样我们就不必重新定义数据库连接、常量等(应用 DRY 原则)。

We setup our integration tests like the following.

我们设置我们的集成测试如下。

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

I can make it run locally using @ActiveProfiles, but this is hard-coded and causes our tests to fail on the build server.

我可以使用 使其在本地运行@ActiveProfiles,但这是硬编码的,会导致我们的测试在构建服务器上失败。

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

I also tried using the @WebAppConfigurationhoping that it might somehow import the spring.profiles.activeproperty from Maven, but that does not work.

我也尝试使用@WebAppConfiguration希望它可能以某种方式spring.profiles.active从 Maven导入属性,但这不起作用。

One other note, we also need to configure our code so that developers can run the web app and then run the tests using IntelliJ's test runner (or another IDE). This is much easier for debugging integration tests.

另一个注意事项,我们还需要配置我们的代码,以便开发人员可以运行 Web 应用程序,然后使用 IntelliJ 的测试运行器(或其他 IDE)运行测试。这对于调试集成测试要容易得多。

采纳答案by Sam Brannen

As other people have already pointed out, you can opt to use Maven to set the spring.profiles.activesystem property, making sure notto use @ActiveProfiles, but that's not convenient for tests run within the IDE.

正如其他人已经指出的那样,您可以选择使用 Maven 来设置spring.profiles.active系统属性,确保不要使用@ActiveProfiles,但这对于在 IDE 中运行的测试来说并不方便。

For a programmatic means to set the active profiles, you have a few options.

对于设置活动配置文件的编程方式,您有几个选项。

  1. Spring 3.1: write a custom ContextLoaderthat prepares the context by setting active profiles in the context's Environment.
  2. Spring 3.2: a custom ContextLoaderremains an option, but a better choice is to implement an ApplicationContextInitializerand configure it via the initializersattribute of @ContextConfiguration. Your custom initializer can configure the Environmentby programmatically setting the active profiles.
  3. Spring 4.0: the aforementioned options still exist; however, as of Spring Framework 4.0 there is a new dedicated ActiveProfilesResolverAPI exactly for this purpose: to programmatically determine the set of active profiles to use in a test. An ActiveProfilesResolvercan be registered via the resolverattribute of @ActiveProfiles.
  1. Spring 3.1:编写一个自定义ContextLoader,通过在上下文的Environment.
  2. 春季3.2:自定义ContextLoader仍是一个选项,而是一种更好的选择是实现一个ApplicationContextInitializer通过和配置它initializers的属性@ContextConfiguration。您的自定义初始值Environment设定项可以通过以编程方式设置活动配置文件来配置。
  3. Spring 4.0:上述选项仍然存在;但是,从 Spring Framework 4.0 开始,有一个专门ActiveProfilesResolver用于此目的的新API:以编程方式确定要在测试中使用的活动配置文件集。一个ActiveProfilesResolver可以通过注册resolver的属性@ActiveProfiles

Regards,

问候,

Sam (author of the Spring TestContext Framework)

Sam(Spring TestContext 框架的作者)

回答by ElderMael

If you want to avoid hard-coding the profile you may want to use the system propertyspring.profiles.activeand set it to whatever you need in that particular environment e.g. we have "dev", "stage" and "prod" profiles for our different environments; also we have a "test", "test-local" and "test-server" profiles for our testing.

如果您想避免对配置文件进行硬编码,您可能需要使用系统属性spring.profiles.active并将其设置为您在该特定环境中需要的任何内容,例如我们为不同环境提供“dev”、“stage”和“prod”配置文件;我们还有用于测试的“测试”、“本地测试”和“测试服务器”配置文件。

Remember that you can have more than one profile in that system property by using a list of comma-separated values e.g. "test,test-qa".

请记住,通过使用逗号分隔值列表(例如“test,test-qa”),您可以在该系统属性中拥有多个配置文件。

You can specify system properties in a maven project in the maven surefire pluginor passing them like this:

您可以在maven surefire 插件中的 maven 项目中指定系统属性,或者像这样传递它们:

mvn -DargLine="-DpropertyName=propertyValue"

回答by Przemek Nowak

As @ElderMael mentioned you could use the argLine property of maven surefire plugin. Often when I need to run all the test with different specific Spring profiles I define additional maven profile. Example:

正如@ElderMael 提到的,您可以使用 maven surefire 插件的 argLine 属性。通常,当我需要使用不同的特定 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>

With that approach you could easily run all the test with activated profile by maven command:

使用这种方法,您可以通过 maven 命令轻松地使用激活的配置文件运行所有测试:

mvn clean test -Pfoo

The @ActiveProfile annotation is good but sometimes we need to run all the test with activated specific profiles and with hard-coded @ActiveProfile parameters it is a problem.

@ActiveProfile 注释很好,但有时我们需要使用激活的特定配置文件和硬编码的 @ActiveProfile 参数运行所有测试,这是一个问题。

For example: by default integration test with H2 in-memory db, but sometimes you want to run test on the "real" database. You could define that additional maven profile and define Jenkins job. With SpringBoot you could also put additional properties to test/resources with name application-foo.yml (or properties) and those properties will be taken into account to.

例如:默认情况下使用 H2 内存数据库进行集成测试,但有时您想在“真实”数据库上运行测试。您可以定义额外的 Maven 配置文件并定义 Jenkins 作业。使用 SpringBoot,您还可以将其他属性添加到名为 application-foo.yml(或属性)的测试/资源中,这些属性将被考虑在内。

回答by Jim Cox

I had a similar problem: I wanted to run all of my integration tests with a default profile, but allow a user to override with a profile that represented a different environment or even db flavor without having to change the @ActiveProfiles value. This is doable if you are using Spring 4.1+ with a custom ActiveProfilesResolver.

我有一个类似的问题:我想使用默认配置文件运行我的所有集成测试,但允许用户使用代表不同环境甚至数据库风格的配置文件进行覆盖,而无需更改 @ActiveProfiles 值。如果您使用带有自定义 ActiveProfilesResolver 的 Spring 4.1+,这是可行的。

This example resolver looks for a System Property, spring.profiles.active, and if it does not exist it will delegate to the default resolver which simply uses the @ActiveProfiles annotation.

此示例解析器查找系统属性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);
    }
}

}

}

And in your test classes, you would use it like this:

在你的测试类中,你会像这样使用它:

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

You can of course use other methods besides checking for the existence of a System Property to set the active profiles. Hope this helps somebody.

除了检查系统属性是否存在之外,您当然可以使用其他方法来设置活动配置文件。希望这可以帮助某人。

回答by cheesus

there are many faces to this problem. in my case, a simple addition to build.gradle already helped:

这个问题有很多方面。就我而言,对 build.gradle 的简单添加已经有所帮助:

test { systemProperties = System.properties }