在Spring配置中模拟命名的豆而不使用allow-bean-definition-overriding吗?

问题描述

我有两个具有相同签名的bean。命名它们是为了获得正确的实例给请求它们的类。

@Configuration
public class MyConfiguration {
  @Bean("durationForX")
  public Duration durationForX() {
    return Duration.ofSeconds(1);
  }

  @Bean("durationForY")
  public Duration durationForY() {
    return Duration.ofSeconds(5);
  }
}

并用作

@Component
public class MyService {
  public MyService(
     @Qualifier("durationForX") duration
  ) {
     ...
  }
}

和Y相似。

现在,我想在集成测试中自动装配上述bean的模型。我尝试了以下

@Configuration
@Profile("my-test-profile")
public class IntegrationTestConfiguration {
  @Primary
  @Bean("durationForX")
  public Duration durationForXMock() {
    return Duration.ofMillis(100);
  }

  @Primary
  @Bean("durationForY")
  public Duration durationForYMock() {
    return Duration.ofMillis(500);
  }

  @Primary
  @Bean
  public AnotherService anotherService() {
     // This one works as expected,probably because it is not a named bean
     ...
  }
}

在运行集成测试时会导致错误消息

***************************
APPLICATION Failed TO START
***************************

Description:

The bean 'durationForX',defined in class path resource [com/../../MyConfiguration.class],Could not be registered. A bean with that name has already been defined in class path resource [com/.../.../IntegrationTestConfiguration.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-deFinition-overriding=true

在集成测试中,我并不会自动装配实例本身,只有一个入口可以调用该应用程序。

@SpringBoottest(webEnvironment = SpringBoottest.WebEnvironment.DEFINED_PORT,classes = {MyApp.class})
@ActiveProfiles("it")
class MyIntegrationTest {
    @Autowired
    GraphQLTestTemplate graphQL;

   ...
}

我不太希望将bean覆盖设置为true,因为我想控制在哪里使用哪些bean。我希望模拟命名的bean遵循与未命名的bean相同的模式,这是为什么呢?有任何解决方法的想法吗?

解决方法

我建议使用其他配置文件进行测试,例如,您可以在主application.yml中为主要应用程序定义值

application.yml

duration1:1
duration2:5

然后使用MyConfiguration注释在@Value类中阅读它们

@Configuration
public class MyConfiguration {


    @Value("${duration1})
    private Integer duration1;

    @Value("${duration2})
    private Integer duration2;

    @Bean("durationForX")
    public Duration durationForX() {
         return Duration.ofSeconds(duration1);
    }

    @Bean("durationForY")
    public Duration durationForY() {
       return Duration.ofSeconds(duration2);
   }

}

现在进行测试,在application-test.ymlsrc/main/resources下创建src/test/resources,然后添加具有测试值的属性

application-test.yml

duration1:100
duration2:500

不需要任何IntegrationTestConfiguration文件,您只需在test.yml文件中维护测试属性

注意::请确保使用@Profile("test")@SpringBootTest注释测试类以加载具有相应测试属性的测试应用程序复制上下文。

@SpringBootTest
@Profile("test)
public class AppTest {

  }