简体   繁体   English

具有多种配置的 Spring Boot 测试

[英]Spring boot test with multiple configuration

In my Spring boot 2.1 project I have different @Configuration s for different test (ConfigurationA and ConfigurationB), that reside in different packages.在我的 Spring boot 2.1 项目中,我有不同的@Configuration用于不同的测试(ConfigurationA 和 ConfigurationB),它们驻留在不同的包中。 Both configurations define the same set of beans but in a different manner (mocked vs. the real thing)两种配置都定义了相同的 bean 集,但方式不同(模拟与真实)

As I am aware of the Bean overriding mechanism introduced in Spring Boot 2.1, I have set the property: spring.main.allow-bean-definition-overriding=true .由于我知道 Spring Boot 2.1 中引入的Bean 覆盖机制,因此我设置了属性: spring.main.allow-bean-definition-overriding=true

However I do have a test with the following the setup of the following configuration and test class.但是,我确实对以下配置和测试类的设置进行了测试。 First there is a @Configuration in the productive part (I'm using Maven):首先在生产部分有一个@Configuration (我使用的是 Maven):

package com.stackoverflow;

@Configuration
public class ProdConfiguration{
...
}

Then in the test branch there is a general Test @Configuration on the same package level:然后在 test 分支中,在同一包级别上有一个通用的 Test @Configuration

package com.stackoverflow

@Configuration
public class TestConfiguration {
  @Bean
  public GameMap gameMap() {
    return Mockito.mock(GameMap.class);
  }
}

And in a subpackage I have another @Configuration :在一个子包中,我有另一个@Configuration

package com.stackoverflow.impl;

@Configuration
public class RealMapTestConfiguration {
  @Bean
  public GameMap gameMap() {
    return new GameMap("testMap.json");
  }
}

And then of course there is the test that is troubling me:然后当然还有让我烦恼的测试:

package com.stackoverflow.impl;

@ExtendWith(SpringExtension.class)
@SpringBootTest
@ContextConfiguration(classes={RealMapTestConfiguration.class, ProdConfiguration.class})
@ActiveProfiles("bug") // spring.main.allow-bean-definition-overriding=true
public class MapImageServiceIT {
  @Autowired
  private GameMap map;
} 

It turns out that the injected GameMap into my test is a mock instance from TestConfiguration instead of the real thing from RealMapTestConfiguration .事实证明,注入到我的测试中的GameMap是来自TestConfiguration的模拟实例,而不是来自RealMapTestConfiguration的真实RealMapTestConfiguration Aparrently in my test I have the configuration from ProdConfiguration and TestConfiguration , when I wanted ProdConfiguration and RealMapTestConfiguration . Aparrently 在我的测试中,当我想要ProdConfigurationRealMapTestConfiguration时,我有ProdConfigurationTestConfiguration的配置。 As the beans defined in the ProdConfiguration and *TestConfiguration are different the combination works, but TestConfiguration and RealMapTestConfiguration define the same been.由于ProdConfiguration*TestConfiguration中定义的 beans 不同,组合工作,但TestConfigurationRealMapTestConfiguration定义相同。 It seems like the TestConfiguration is picked up by component scanning as it is in the same package as ProdConfiguration .似乎TestConfiguration是通过组件扫描获取的,因为它与ProdConfiguration位于同一包中。 I was under the impression that when overriding beans the bean definition that is closer to the test class would be preferred.我的印象是,当覆盖 bean 时,更接近测试类的 bean 定义将是首选。 However this seems not to be the case.然而,情况似乎并非如此。

So here are my questions:所以这里是我的问题:

  1. When overriding beans, what is the order?覆盖 bean 时,顺序是什么? Which bean overrides which one?哪个 bean 覆盖了哪个 bean?
  2. How to go about to get the correct instance in my test (using a different bean name is not an option, as in reality the injected bean is not directly used in the test but in a service the test uses and there is no qualifier on it.)如何在我的测试中获得正确的实例(使用不同的 bean 名称不是一种选择,因为实际上注入的 bean 不是直接在测试中使用,而是在测试使用的服务中使用,并且上面没有限定符.)

I've not used the spring.main.allow-bean-definition-overriding=true property, but specifying specific config in a test class has worked fine for me as a way of switching between objects in different tests.我没有使用spring.main.allow-bean-definition-overriding=true属性,但是在测试类中指定特定配置作为在不同测试中切换对象的一种方式对我来说效果很好。

You say...你说...

It turns out that the injected GameMap into my test is a mock instance from TestConfiguration instead of the real thing from RealMapTestConfiguration.事实证明,注入到我的测试中的 GameMap 是来自 TestConfiguration 的模拟实例,而不是来自 RealMapTestConfiguration 的真实实例。

But RealMapTestConfiguration does return a mock但是 RealMapTestConfiguration 确实返回了一个模拟

package com.stackoverflow.impl;

@Configuration
public class RealMapTestConfiguration {
  @Bean
  public GameMap gameMap() {
    return Mockito.mock(GameMap.class);
  }
}

I think the problem here is that including ContextConfiguration nullifies (part of) the effect of @SpringBootTest .我认为这里的问题是包含ContextConfiguration @SpringBootTest (部分) @SpringBootTest的效果@SpringBootTest @SpringBootTest has the effect of looking for @SpringBootConfiguration in your application (starting from the same package, I believe). @SpringBootTest有寻找效应@SpringBootConfiguration在您的应用程序(从同一个包开始,我相信)。 However, if ContextConfiguration is applied, then configurations are loaded from there.但是,如果应用了ContextConfiguration ,则从那里加载配置。

Another way of saying that: because you have ContextConfiguration in your test, scanning for @Configuration classes is disabled, and TestConfiguration is not loaded.另一种说法是:因为您的测试中有ContextConfiguration ,所以禁用了对@Configuration类的扫描,并且不会加载TestConfiguration

I don't think I have a full picture of your configuration setup so can't really recommend a best practice here, but a quick way to fix this is to add TestConfiguration to your ContextConfiguration in your test.我不认为我对您的配置设置有一个完整的了解,所以在这里不能真正推荐最佳实践,但解决这个问题的快速方法是在您的测试中将TestConfiguration添加到您的ContextConfiguration Make sure you add it last, so that it overrides the bean definitions in the other two configurations.确保最后添加它,以便它覆盖其他两个配置中的 bean 定义。

The other thing that might work is removing @ContextConfiguration entirely and letting the SpringBootApplication scanning do its thing - that's where what you said about the bean definition that is closest may apply.另一件事可能是完全删除@ContextConfiguration并让SpringBootApplication扫描完成它的工作 - 这就是您所说的最接近的 bean 定义可能适用的地方。

In that case just don't use @Configuration on configuration class and import it to the test manually using @Import, example:在这种情况下,不要在配置类上使用 @Configuration 并使用 @Import 手动将其导入测试,例如:

@SpringBootTest
@Import(MyTest.MyTestConfig.class)
public class MyTest {

    @Autowired
    private String string;

    @Test
    public void myTest() {
        System.out.println(string);
    }

    static class MyTestConfig {
        @Bean
        public String string() {
            return "String";
        }
    }
}

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

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