具有MapStruct的@SpringBootTest需要Impl

问题描述

我进行了以下测试:

@SpringBoottest(classes = {SomeService.class,DtoMapperImpl.class})
class SomeServiceTest {

以及以下映射器:

@Mapper(componentModel = "spring")
public interface DtoMapper {
    EntityDto toDto(Entity entity);
}

我没有更改软件包(这意味着 DtoMapperImpl DtoMapper 位于同一软件包中)

将Impl更改为接口后,我的测试就会失败:

@SpringBoottest(classes = {SomeService.class,DtoMapper.class})
class SomeServiceTest {

原因: org.springframework.beans.factory.UnsatisfiedDependencyException: 创建名称为“ someService”的bean时出错:不满意的依赖关系 通过构造函数参数2表示;嵌套异常为 org.springframework.beans.factory.NoSuchBeanDeFinitionException:否 可用类型为“ DtoMapper”的合格Bean:预计至少为1 符合自动装配候选条件的bean。依赖项注释:{}

能否请您提出解决此问题的最佳方法?我正在使用MapStruct 1.3.1.Final

解决方法

创建以下配置(应该指出映射器的位置):

@TestConfiguration
@ComponentScan("some.package.mapper")
public class MappersConfig {
}

并修改切片:

@SpringBootTest(classes = {SomeService.class,MappersConfig.class})
class SomeServiceTest {
,

问题实际上与MapStruct无关,而与SpringBootTest#classes的使用方式有关。

classes中的SpringBootTest旨在提供应在测试中加载的组件。

来自JavaDoc:

用于加载ApplicationContext的组件类。也可以使用@ContextConfiguration(classes=...)指定。如果未定义显式类,则测试将寻找嵌套的@Configuration类,然后退回到@SpringBootConfiguration搜索。 返回值: 用于加载应用程序上下文的组件类

在您的情况下,您有2个课程:

  • SomeService-我假设这是一个用@Service注释的类,Spring会正确地加载它
  • DtoMapper-这是MapStruct映射器,它是一个接口,不是组件。您要测试的组件是DtoMapperImpl

您可以通过以下几种方法来解决此问题:

使用Impl类

您可以在DtoMapperImpl中使用SpringBootTest#classes(Spring Component类),然后您的测试将加载正确的组件

使用自定义配置类,该类将对您的映射器进行组件扫描

@TestConfiguration
@ComponentScan("com.example.mapper")
public class MappersConfig {

}

然后在您的SpringBootTest#classes中使用它。例如

@SpringBootTest(classes = {SomeService.class,MappersConfig.class})
class SomeServiceTest {
   ...
}