【问题标题】:MapStruct+Spring+Junit : Inject mapper into service class testMapStruct+Spring+Junit : 将映射器注入服务类测试
【发布时间】:2023-01-15 08:56:51
【问题描述】:

我正在使用 Spring Boot、MapStruct (1.5.3.Final) 和 JUnit。 我想将映射器注入服务类测试。 我不想存根这个映射器(when(..).thenReturn(...))。

我尝试了很多东西并阅读了 Stackoverflow 上的多篇文章,但我发现了任何东西。

我的映射器:

@Mapper(
        componentModel = MappingConstants.ComponentModel.SPRING,
        injectionStrategy = InjectionStrategy.CONSTRUCTOR
)
public interface ReservationMapper {

    @Mapping(target = "id", ignore = true)
    Reservation getReservationFrom(NewReservationSentByClient reservationData);

    ExistingReservation getExistingReservationFrom(Reservation reservation);
}

使用此映射器的服务:

@Service
@RequiredArgsConstructor
@Slf4j
public class StandardReservationService implements ReservationService{
    private final ReservationMapper reservationMapper;
  ...

测试类

@RunWith(SpringRunner.class)
@SpringBootTest(classes={ReservationMapper.class})
public class StandardReservationServiceTest {

    @MockBean
    private ReservationRepository reservationRepositoryMock;
    @Autowired
    private ReservationMapper reservationMapperMock;
    @MockBean
    private ReservationRulesRepository reservationRulesRepositoryMock;
    @Autowired
    private StandardReservationService service;


    @ParameterizedTest
    @EnumSource(ReservationSource.class)
    public void ...

pom.xml

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>

        <!-- TESTS -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.17</source>
                    <target>1.17</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${org.mapstruct.version}</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok-mapstruct-binding</artifactId>
                            <version>0.2.0</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>

        </plugins>
    </build>

我试过了 :

  • 在@SpringBootTest(classes={..}) 中传递 ReservationMapperImpl.class 但是当我全新安装时找不到这个实现
  • 手动实例化 Reservation MapperImpl 但在我全新安装时出现同样的问题
  • ...等等

如果可能的话,我不想使用@SpringBootTest,因为我正在编写单元测试,所以我不需要上下文……但我不想手动创建对象映射并将其存根。

【问题讨论】:

    标签: spring-boot junit mapstruct


    【解决方案1】:

    我认为您别无选择,只能使用带有 spring 上下文的测试,因为您使用的是 Spring 组件模型。我认为问题在于,实际测试不会扫描您的映射器 (ReservationMapperImpl) 的实现。

    我建议您在映射器的包上使用组件扫描进行测试。你不需要为此使用@SpringBooTest,你也可以使用@SpringJunitConfig(TestMappingConfig.class)和这样的示例测试配置:

    @ComponentScan("package.of.the.mapper")
    public class YouTestMappingConfig {
    
    }
    

    这将扫描两者,ReservationMapper 将不会被拾取,因为它没有 @Component|Service|Bean 注释,但是 ReservationMapperImpl 具有 @Component 注释并将被拾取用于测试应用程序上下文。

    【讨论】:

      【解决方案2】:

      你应该试试

      private ReservationMapper reservationMapper = Mappers.getMapper(ReservationMapper.class);
      

      并删除 @Autowired 注释。这应该为您提供映射器的真正实现。

      【讨论】:

      • 我完全按照你说的做了,但它不起作用,我有错误:org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '...StandardReservationServiceTest': Unsatisfied dependency expressed through field 'service'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '...StandardReservationService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
      • 在这种情况下,您可以尝试添加 @Spy 注释
      • 或者尝试在所需服务中通过构造函数注入来注入此处创建的映射器
      • 我不明白你最后的评论
      • 您不必使用@Autowired 批注来获取您可以在测试中简单创建的服务,就像您通常使用new 生成java 类一样。然后可以通过注入它们来手动满足该服务的依赖性..... 另外请注意,您应该将@SpringBootTest(classes={ReservationMapper.class})替换为@SpringBootTest。您最新的错误消息表明您在测试环境中没有可用的所需服务。通过显式添加 classes 关键字,默认情况下所有其他类都被排除在外。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-03
      • 2017-12-29
      • 2019-05-05
      • 2020-10-24
      • 2021-01-04
      • 2017-10-30
      • 1970-01-01
      相关资源
      最近更新 更多