通过Setter注入Service的MapStruct mapper导致项目测试失败
你通过Setter注入方式在MapStruct抽象Mapper中注入MyService,项目编译运行正常,但执行非映射相关测试时出现以下错误:
原因:org.springframework.beans.factory.UnsatisfiedDependencyException: 创建名为'myMapperImpl'的Bean时出错:通过方法'setBmdMappingService'参数0表达的依赖不满足;嵌套异常是org.springframework.beans.factory.NoSuchBeanDefinitionException:找不到类型为'***.MyService'的合格Bean:期望至少有1个符合自动注入候选条件的Bean。依赖注解:{}
这是因为测试环境中Spring上下文没有正确加载MyService Bean,或者Mapper的注入方式在测试场景下存在兼容性问题,可通过以下几种方式解决:
1. 针对单元测试:手动Mock并注入依赖
如果是非Spring上下文的单元测试,Spring不会自动管理Bean,需要手动MockMyService并注入到生成的Mapper实现类中:
@ExtendWith(MockitoExtension.class) public class MyMapperTest { @Mock private MyService myService; private MyMapper myMapper; @BeforeEach void setUp() { // 获取MapStruct生成的Mapper实例 myMapper = Mappers.getMapper(MyMapper.class); // 强制转换为实现类,调用Setter注入Mock对象 ((MyMapperImpl) myMapper).setMyService(myService); } // 编写测试逻辑... }
2. 改用构造函数注入(推荐)
MapStruct结合Spring使用时,构造函数注入是更稳妥的方式,既符合Spring官方规范,也能避免测试中依赖未初始化的问题。修改Mapper代码:
// 指定componentModel为spring,让生成的实现类被Spring管理 @Mapper(componentModel = "spring") public abstract class MyMapper { private final MyService myService; // 构造函数注入,Spring会自动装配MyService protected MyMapper(MyService myService) { this.myService = myService; } // 你的映射方法... }
3. 针对集成测试:补充上下文Bean
如果测试需要加载Spring上下文,可通过@MockBean给测试上下文添加MyService的Mock实例,避免找不到Bean的问题:
@SpringBootTest public class NonMappingTest { // 向Spring上下文注入Mock的MyService @MockBean private MyService myService; // 测试逻辑... }
另外还要检查:MyService类是否添加了@Service注解,测试类的扫描路径是否包含MyService所在的包,确保Spring能扫描到这个Bean。
内容的提问来源于stack exchange,提问作者Battalgazi

