如何在Spring Boot和JUnit测试中定义spring.config.location?

时间:2018-09-03 00:33:03

标签: spring-boot junit spring-boot-test

在运行JUnit测试时,如何通过编程方式配置Spring Boot以为spring.config.namespring.config.location属性定义新值?

例如,如果我们想在运行应用程序本身时定义这些属性,则可以使用类似的内容(在Kotlin中):

fun main(args: Array<String>) {
//  SpringApplication.run(Application::class.java, *args)

    val applicationContext = SpringApplicationBuilder(Application::class.java)
        .properties(
            """spring.config.name:
                ${getSpringConfigNames()}
            """,
            """spring.config.location:
                ${getSpringConfigLocationPaths()}
            """
        )
        .build()
        .run(*args)

//  val environment = applicationContext.getEnvironment()
}

但是我无法找到一种方法来配置它以便在JUnit测试中使用。

修改

由于弹簧靴的限制,这里很复杂。

我想使用整个文件夹及其子文件夹作为搜索配置文件的有效位置(例如,我们可以拥有用于特定环境,数据库,第三方等的文件夹)。

运行应用程序时,可以创建一个方法,在这种情况下为getSpringConfigLocationPaths()。然后,该方法会创建一个用逗号分隔的列表,其中所有文件夹都位于“主”文件夹中。

例如,对于主文件夹src/main/resources/configuration,它将输出:

src/main/resources/configuration,
src/main/resources/configuration/environments,
src/main/resources/configuration/environments/development,
src/main/resources/configuration/environments/staging,
src/main/resources/configuration/environments/testing,
src/main/resources/configuration/environments/production,
src/main/resources/configuration/environments/common

在使用JUnit测试和Spring Boot时如何解决这种情况?

很遗憾,Spring Boot不允许使用src/main/resources/configuration/**/*之类的东西。

因为我们已经在不同的子文件夹中组织了带有几个属性文件的系统,所以我们需要找到一种方法来对其进行深入研究。

3 个答案:

答案 0 :(得分:2)

应该仔细设计运行弹簧靴的测试, 有一个用于弹簧启动测试的完整测试框架,因此显然可以考虑使用此框架。

在配置管理方面,我建议考虑以下因素:

基本上有两种类型的测试:

  • 测试加载具体的特定配置(一组Bean),例如,如果您只想测试DAO,则为此dao加载配置。 在这种情况下,应根据特定测试的需要“量身定制”某种配置,而无需“完全”配置。

例如,如果微服务包含数据库(用户,密码,架构等)的配置以及消息传递管理(例如,消息传递管理),则在测试DAO,消息传递时无需指定消息传递系统的配置无论如何都不会加载bean。

通常,这种“类型”的测试如下所示:

@SpringBootTest(classes = {RelationalDbDaoConfiguration.class}) 
public class MyDaoTest {

}

如果您没有需要的配置,则可以使用@MockBean模拟不必要的bean,甚至可以在src/test/java中创建自定义配置,使其仅在测试类路径中。使用@TestConfiguration很有道理,但这超出了问题的范围。

现在,仅为了加载db的配置,有很多选项,仅举几例:

    在测试类上
  • @ActiveProfiles(“ dao”)+将“ application-dao.properties/yaml”放入src/test/resourcessrc/test/resources/config

  • 在测试中使用@TestPropertySource(locations = "classpath:whatever.properties")

  • 创建一个特殊的“ DbProperties” bean并在春季以编程方式对其进行初始化,当您知道一些有关仅在实际测试执行期间运行测试的上下文的详细信息时,这才有意义。在测试之前创建一个数据库,并动态创建端口,但它的设置确实相当先进,超出了此问题的范围)+数据源bean可以读取这些属性

  • 使用@SpringBootTest的{​​{1}}属性提供“细粒度”属性定义

  • 显而易见,但无论如何我都会提到:将properties放在application.properties中,它将覆盖常规配置

第二种测试类型是当您加载“整个”微服务时,通常,这些测试在src/test/resources批注中没有“ classes”参数

@SpringBootTest

现在,尽管实际上指定这些配置的技术仍然适用(只是配置文件的内容会有所不同),但这肯定需要指定一整套配置。

我不建议在测试过程中使用spring.config.location,因为这意味着测试依赖于某些外部资源,这会使整个设置更加复杂。

答案 1 :(得分:1)

如果是XML驱动的配置,

@ContextConfiguration(locations = "/app-context.xml")

如果注释是由配置类驱动的,

@ContextConfiguration(classes = {AppCOnfig::class, AnotherCOnfig::class}

这些将在您运行的单元测试类的类级别上定义。

此外,如果您有个人资料供Junit考虑, @ActiveProfiles("myProfile")将被添加到测试类中。

答案 2 :(得分:0)

我使用的是最新的Spring Boot 2.2.0,根据我的经验,@TestPropertySource@SpringBootTest注释都可以完成此任务,因为它们具有properties属性。 因此,您可以执行以下操作:

@TestPropertySource(properties = ["spring.config.location=classpath:dev/", "spring.config.name=custom-app-name"]
@TestConfiguration
class DevTestCfg {} // this will make tests to look for configs in resources/dev/custom-app-name.properties

还要注意,如果您希望从多个位置加载属性,则有一个spring.config.additional-location属性。

这里唯一的问题是properties属性中的值必须恒定。 但是您可以为每个环境创建多个配置,并将相应的@Profile("envName")放在每个配置类上。然后使用不同的-Dspring.profiles.active运行测试,应自动选择相应的测试配置。