You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Spock+MongoDB Testcontainer编写Spring Service集成测试的Bean注入错误?

问题描述

我有一个Spring Service类:

@Service
public class MyService {
  @Autowired OtherService otherService;
  @Autowired MyRepository myRepository;

  // some methods...
}

其中myRepository实现了MongoRepository。

我想用Groovy和Spock编写集成测试,要求:

  • otherService需要被Mock
  • myRepository自动装配并使用Testcontainer的MongoDB

我写了如下测试代码:

@SpringBootTest(classes = [MyService.class, MyRepository.class])
@Testcontainers
class MyServiceIntegrationTest extends Specification {
  @Shared 
  static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.4.3")

  @Autowired 
  MyRepository myRepository

  @SpringBean 
  OtherService otherService = Mock()

  @Autowired 
  MyService testedService

  @DynamicPropertySource
  static mongoProps(DynamicPropertyRegistry registry) {
    mongoDBContainer.start()
    registry.add("spring.data.mongodb.uri", () -> mongoDBContainer.getReplicaSetUrl())
  }

  // some tests...
}

但运行时报错:

Error creating bean with name 'myService': Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'com.xxx.xxx.MyRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

请问如何修改才能让测试正常运行?


问题分析与解决办法

这个报错的核心原因很明确:你在@SpringBootTest里只指定了MyService和MyRepository两个类,但Spring Data MongoDB要生成MongoRepository的代理实例,需要依赖一系列自动配置类(比如MongoDB连接配置、Repository代理生成逻辑等),仅把MyRepository加入测试配置,Spring根本不知道怎么创建它的实例。

给你两种可行的修改方案,按需选择:

方案一:手动引入MongoDB自动配置类

直接把MongoDB相关的核心自动配置类加到@SpringBootTest的classes参数中,让Spring能正确初始化MyRepository:

@SpringBootTest(classes = [MyService.class, MyRepository.class, MongoDataAutoConfiguration.class, MongoAutoConfiguration.class])
@Testcontainers
class MyServiceIntegrationTest extends Specification {
  @Shared 
  static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.4.3")

  @Autowired 
  MyRepository myRepository

  @SpringBean 
  OtherService otherService = Mock()

  @Autowired 
  MyService testedService

  @DynamicPropertySource
  static mongoProps(DynamicPropertyRegistry registry) {
    // 划重点:不用手动调用start()!@Testcontainers会自动管理容器的启动和停止
    registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl)
  }

  // some tests...
}

方案二:加载主应用配置类(更推荐)

如果你不想手动拼凑配置类,最简单的方式是让测试加载项目中的主应用配置类(就是带有@SpringBootApplication的那个类)。这样Spring会自动引入所有必要的MongoDB配置,同时@SpringBean会自动替换掉容器中原有的OtherService为Mock实例,完美匹配你的需求:

// 把YourSpringBootApplication换成你项目实际的主应用类
@SpringBootTest(classes = YourSpringBootApplication.class)
@Testcontainers
class MyServiceIntegrationTest extends Specification {
  @Shared 
  static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.4.3")

  @Autowired 
  MyRepository myRepository

  @SpringBean 
  OtherService otherService = Mock()

  @Autowired 
  MyService testedService

  @DynamicPropertySource
  static mongoProps(DynamicPropertyRegistry registry) {
    registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl)
  }

  // some tests...
}

这种方式更简洁,符合Spring Boot的自动配置设计理念,后续维护成本也更低。

额外提醒

  • 确保MyRepository所在的包能被Spring扫描到:要么它在主应用类的子包下,要么你在主应用类上用@EnableMongoRepositories指定了Repository的扫描路径。
  • 建议把MyService的字段注入改成构造函数注入,这是Spring官方推荐的方式,测试时的依赖注入逻辑会更稳定。

内容的提问来源于stack exchange,提问作者Wiktor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 16:45:29