简体   繁体   English

Spring Boot:如何覆盖单元测试中的默认属性

[英]Spring Boot: How to override default properties in Unit tests

I tried loading a second properties file for my unit tests, that would overwrite some properties. 我尝试为我的单元测试加载第二个属性文件,这将覆盖一些属性。

Loading it with @PropertySource on a @Configuration didn't work, loading it with @TestPropertySource didn't work either. @Configuration上使用@PropertySource加载它不起作用,使用@TestPropertySource加载它也不起作用。 Only setting properties directly on @TesPropertySource works, but it does NOT work when I try to make it into a meta-annotation. 只能直接在@TesPropertySource上设置properties ,但是当我尝试将其变成元注释时,它不起作用。

Here is an example project: https://github.com/cptwunderlich/SpringTestProperties 这是一个示例项目: https//github.com/cptwunderlich/SpringTestProperties

I'd prefer to load one file an affect all tests (eg with @PropertySource ), but if that doesn't work, at least having a custom meta-annotation would be nice, so I don't have to put that on each and every test. 我更喜欢加载一个文件影响所有测试(例如使用@PropertySource ),但如果这不起作用,至少有一个自定义元注释会很好,所以我不必把它放在每个和每一次测试。 Basically I want to not import some data into the DB for the tests (spring.datasource.data) and later also change the database used - without copying the whole config and having to change it in two places each time. 基本上我想一些数据不能导入到数据库的测试(spring.datasource.data)后来也改变使用的数据库-而不复制整个配置,不得不改变它在每次两个地方。

The important bits: 重要的一点:

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(locations = "classpath:application-test.properties")
public class TestconfigApplicationTests {

    @Value("${my.test.property}")
    private String testproperty;

    @Test
    public void assertValue() {
        Assert.assertEquals("foobar", testproperty);
    }

}

Alternatively the config class in the tests package : 或者, 测试包中的config类:

@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
@PropertySource("classpath:application-test.properties")
public class GlobalTestConfig {
}

Update: 更新:

The main suggestion in the answers is to use @ActiveProfile to activate a 'test' profile which will result in loading 'application-test.yaml'. 答案中的主要建议是使用@ActiveProfile激活'test'配置文件,这将导致加载'application-test.yaml'。 That's bettern than @TestPropertySource , but I still need to put an annotation on each Test Class. 这比@TestPropertySource ,但我仍然需要在每个Test Class上添加一个注释。 I tried creating a meta-annotation - which should work - so at least I only have one custom annotation where I could bundle other settings. 我尝试创建一个元注释 - 它应该工作 - 所以至少我只有一个自定义注释,我可以捆绑其他设置。 But that doesn't work. 但这不起作用。

The perfect solution would set these setting globally with one config class, instead of having to put an annotation on each test. 完美的解决方案是使用一个配置类全局设置这些设置,而不必在每个测试上添加注释。 I'm still looking for that solution, or at least debugging the meta-annotation before closing this question. 我仍然在寻找这个解决方案,或者至少在关闭这个问题之前调试元注释。 Edit: I've created a Jira issue: SPR-17531 编辑:我创建了一个Jira问题:SPR-17531

Edit 编辑

OK, I got a bit confused, so I retested all the different combinations: 好吧,我有点困惑,所以我重新测试了所有不同的组合:

  • @TestPropertySource(locations = "classpath:application-test.properties") on the Test, actually works now. @TestPropertySource(locations = "classpath:application-test.properties")上的测试,实际上现在的作品 huh. 呵呵。
  • @ActiveProfiles("test") on the Test works. 关于测试工作的@ActiveProfiles("test")
  • Meta-annotation with @ActiveProfiles does not work. 元注解与@ActiveProfiles 不起作用 EDIT: it does... 编辑:它确实......
  • Global config of any sort (TestPropertySource, ActiveProfiles, Propertysource) does not work 任何形式的全局配置(TestPropertySource,ActiveProfiles,Propertysource) 不起作用
  • (Having an application.properties in test/resources also doesn't work, bc. it doesn't overwrite single properties, but the complete file, ie, I'd need to redefine and duplicate everything.) (测试/资源中的application.properties也不起作用,bc。它不会覆盖单个属性,而是覆盖整个文件,即我需要重新定义和复制所有内容。)

EDIT: 编辑:

OK, my mistake. 好的,我的错误。 The meta-annotation DOES work - I forgot to set the retention policy and the default is CLASS. 元注释可行 - 我忘了设置保留策略,默认为CLASS。 Adding @Retention(RUNTIME) fixes that. 添加@Retention(RUNTIME)修复了这个问题。

It doesn't seem like there is a way to globally set this in code (ie, without configuring in my IDE how tests are run), so I'll have to go with the profile for now. 似乎没有办法在代码中全局设置它(即,没有在我的IDE中配置如何运行测试),所以我现在必须使用该配置文件。

You can use @ActiveProfiles("test") . 您可以使用@ActiveProfiles("test") This will set the application-test.yml properties into test environment. 这会将application-test.yml属性设置为测试环境。

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class TestconfigApplicationTests {
    ...
}

If we need to target different environments, there's a build-in mechanism for that in Boot so there is no need for additional libraries or refactorings. 如果我们需要针对不同的环境,那么在Boot中有一个内置机制,因此不需要额外的库或重构。

We can simply define an application-environment.properties file in the src/main/resources directory – and then set a Spring profile with the same environment name. 我们可以简单地在src/main/resources目录中定义application-environment.properties文件 - 然后使用相同的环境名称设置Spring配置文件。

For example, if we define a staging or test environment, that means we'll have to define a staging or test profile and then application-staging.properties or application-test.properties . 例如,如果我们定义一个stagingtest环境,那意味着我们必须定义一个临时或测试配置文件,然后定义application-staging.propertiesapplication-test.properties

This env file will be loaded and will take precedence over the default property file which is application.properties . env文件将被加载,并将优先于默认属性文件application.properties Note that the default file will still be loaded, it's just that when there is a property collision the environment specific property file takes precedence, meaning the properties specified in application-staging.properties or application-test.properties will override the ones in application.properties . 请注意,仍然会加载默认文件,只是当存在属性冲突时,环境特定属性文件优先,这意味着application-staging.propertiesapplication-test.properties指定的属性将覆盖application-staging.properties的属性application.properties

Each test class uses its own profile, so you need to specify the active profile for each class. 每个测试类都使用自己的配置文件,因此您需要为每个类指定活动配置文件。

One additional thing that might be of interest for you is that you can mock services via configuration classes 您可能感兴趣的另一件事是您可以通过configuration类模拟服务

@Configuration
@Profile("mockEntityService")
public class EntityServiceMockProvider {

    @Bean
    @Primary
    public EntityService entityService() {
        EntityService mockedEntityService = Mockito.mock(EntityService.class);

        Entity entity= Mockito.mock(Entity.class);
        when(mockedEntityService.save(any(Entity.class)))
                .thenReturn(entity);

        return mockedEntityService ;
    }
}

In test classes you can use multiple active profiles: eg @ActiveProfiles({"test", "mockEntityService"}) 在测试类中,您可以使用多个活动配置文件:例如@ActiveProfiles({"test", "mockEntityService"})

so instead of using the real implementation of the EntityService you will use the mocked implementation. 因此,您将使用EntityService实现,而不是使用EntityService的实际实现。

You can add application.properties to 您可以将application.properties添加到

src/test/resources

Then all properties which are in this file override these from src/main/resources/application.properties. 然后,此文件中的所有属性都将覆盖src / main / resources / application.properties中的这些属性。

So you don't need profiles and any additional annotations like @TestPropertySource 因此,您不需要配置文件和任何其他注释,如@TestPropertySource

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM