【问题标题】:Mocked named beans in Spring configuration without using allow-bean-definition-overriding?在Spring配置中模拟命名bean而不使用allow-bean-definition-overriding?
【发布时间】:2020-10-19 13:20:37
【问题描述】:

我有两个具有相同签名的 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 遵循与未命名的相同的模式,这是为什么呢?对解决方法有任何想法吗?

【问题讨论】:

    标签: java spring-boot testing mocking javabeans


    【解决方案1】:

    我建议使用不同的配置文件进行测试,例如您可以在 main 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);
       }
    
    }
    

    现在测试在src/main/resourcessrc/test/resources下创建application-test.yml,然后添加带有测试值的属性

    application-test.yml

    duration1:100
    duration2:500
    

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

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

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

    【讨论】:

    • 感谢@Deadpool,我想将这些配置保存在 yml 文件中并让每个配置由单个 bean 使用而不是生产 bean 和模拟 bean 是有意义的。
    • 我仍然有兴趣看看是否有替代解决方案,其中配置不在 yml 文件中。
    猜你喜欢
    • 1970-01-01
    • 2019-04-26
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    相关资源
    最近更新 更多