Spring集成测试与配置文件

23
在我们的Spring web应用中,我们使用Spring bean profiles来区分三种情况:开发、集成和生产。我们使用它们连接到不同的数据库或设置其他常量。
使用Spring bean profiles可以很好地适应Web应用环境的变化。
我们遇到的问题是当我们的集成测试代码需要更改环境时。在这些情况下,集成测试会加载Web应用程序的应用程序上下文。这样,我们就不必重新定义数据库连接、常量等(应用DRY原则)。
我们按以下方式设置我们的集成测试。
@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;
   ...
 }

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

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

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

另外需要注意的是,我们还需要配置代码,使得开发人员可以在IntelliJ的测试运行器(或其他IDE)上运行Web应用程序,然后运行测试。这对于调试集成测试来说更容易。

5个回答

41

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

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

  1. Spring 3.1:编写自定义的ContextLoader,通过设置上下文中的Environment中的活动配置文件来准备上下文。
  2. Spring 3.2: 自定义ContextLoader仍然是一种选择,但更好的选择是实现ApplicationContextInitializer并通过@ContextConfigurationinitializers属性进行配置。您的自定义初始化程序可以通过编程方式设置活动配置文件来配置Environment
  3. Spring 4.0: 上述选项仍然存在;但是,从Spring Framework 4.0开始,有一个新的专用ActiveProfilesResolver API,专门用于此目的:以编程方式确定在测试中要使用的活动配置文件集合。可以通过@ActiveProfilesresolver属性注册ActiveProfilesResolver

敬礼,

Sam(Spring TestContext框架的作者)


我正在使用Spring 3.2,其中第二项非常适用。我设置了我的ApplicationContextInitializer来调用configurableApplicationContext.getEnvironment().setDefaultProfiles("development");,这会在我通过IntelliJ运行测试时运行开发配置文件。 - David V
有没有使用 ActiveProfilesResolver 的示例?我不太清楚如何使用它。 - daydreamer
2
是的,在Spring Framework参考手册的测试章节中,有一个使用自定义ActiveProfilesResolver的示例。 - Sam Brannen
1
在测试类中使用系统属性覆盖@ActiveProfiles时也存在错误:https://jira.spring.io/browse/SPR-8982 - Grigory Kislin
@SamBrannen,还有第四个选项。编写自己的自定义SpringJUnit4ClassRunner。我不得不这样做,因为Spring会非常急切地加载commons logging,如果您想以编程方式配置日志记录,则非常令人恼火。当然,您将不得不维护自己的ClassRunner,但至少您可以控制初始化和缓存。 - Adam Gent

22

我曾遇到类似的问题:我想使用默认配置来运行所有的集成测试,但是如果需要在不改变@ActiveProfiles值得情况下允许用户使用代表不同环境或数据库类型的配置文件进行覆盖。如果您正在使用Spring 4.1+和自定义的ActiveProfilesResolver,则可以实现这一点。

此示例解析器会查找一个名为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 { }

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


7
如果您想避免硬编码配置文件,可以使用系统属性spring.profiles.active,并将其设置为特定环境中所需的内容,例如我们为不同的环境拥有“dev”,“stage”和“prod”配置文件;此外,我们还为测试拥有“test”,“test-local”和“test-server”配置文件。
请记住,您可以通过使用逗号分隔的值列表在该系统属性中拥有多个配置文件,例如“test,test-qa”。
您可以在maven项目中通过maven surefire插件或像这样传递它们来指定系统属性:
mvn -DargLine="-DpropertyName=propertyValue"

1
正如@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>

使用这种方法,您可以通过Maven命令轻松运行所有已激活配置文件的测试:
mvn clean test -Pfoo

@ActiveProfile注解很好,但有时我们需要在激活特定配置文件的情况下运行所有测试,并且使用硬编码的@ActiveProfile参数会导致问题.

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


-1

这个问题有很多方面。

在我的情况下,对build.gradle进行简单的添加已经有所帮助:

test { systemProperties = System.properties }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接