1. 概述

MapStruct 是 Java 项目中一款强大的映射工具库。通过遵循约定优于配置的原则,MapStruct 能让开发者用最少的代码完成复杂对象的映射转换。

本文将演示如何为依赖 MapStruct 生成映射器的类编写单元测试。

2. 环境搭建

在项目中集成 MapStruct,首先需要在 pom.xml 添加 Maven 依赖:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.6.3</version>
</dependency>

此外,针对 Spring 测试场景,还需添加以下模块:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.2.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>6.2.1</version>
    <scope>test</scope>
</dependency>

3. 测试场景准备

映射库的典型用例是持久层操作前的 DTO 与实体转换。

3.1 DTO 定义

定义映射源对象 MediaDto

public class MediaDto {

    private Long id;

    private String title;

    // setters - getters - constructors
}

3.2 实体定义

映射目标对象 Media 实体:

public class Media {

    private Long id;

    private String title;

    // setters - getters - constructors
}

3.3 映射器接口

基于 MediaDtoMedia 定义映射器接口:

@Mapper
public interface MediaMapper {

    MediaDto toDto(Media media);

    Media toEntity(MediaDto mediaDto);
}

✅ 踩坑提醒:本文聚焦测试,不涉及嵌套映射、继承等高级特性。

3.4 Spring Bean 映射器

为兼容 Spring 测试,创建 Spring 托管的映射器:

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface MediaSpringMapper extends MediaMapper {
}

3.5 待测服务类

MediaService 依赖 MediaMapper

public class MediaService {

    private final MediaMapper mediaMapper;

    public Media persistMedia(MediaDto mediaDto) {
        Media media = mediaMapper.toEntity(mediaDto);
        logger.info("Persist media: {}", media);
        return media;
    }

    // getters - setters - constructors
}

4. 使用 Mock 映射器的测试

本节展示如何用 Mock 替代生成映射器进行测试。首先用 Mockito 创建 Mock 映射器:

@Test
public void whenMockedMapperIsUsed_thenMockedValuesAreMapped() {
    MediaMapper mockMediaMapper = mock(MediaMapper.class);
    Media mockedMedia = new Media(5L, "Title 5");
    when(mockMediaMapper.toEntity(any())).thenReturn(mockedMedia);

    MediaService mediaService = new MediaService(mockMediaMapper);
    MediaDto mediaDto = new MediaDto(1L, "title 1");
    Media persisted = mediaService.persistMedia(mediaDto);

    verify(mockMediaMapper).toEntity(mediaDto);
    assertEquals(mockedMedia.getId(), persisted.getId());
    assertEquals(mockedMedia.getTitle(), persisted.getTitle());
}

验证要点:

  • ✅ 确认 toEntity() 方法被调用
  • ✅ 验证返回对象与 Mock 预期一致

Spring 环境测试需先配置上下文:

@Configuration
public class Config {

    @Bean
    public MediaService mediaService(MediaMapper mediaMapper) {
        return new MediaService(mediaMapper);
    }
}

Spring 测试用例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class)
public class MediaServiceSpringMockedMapperTest {

    @Autowired
    MediaService mediaService;

    @MockitoBean
    MediaSpringMapper mockMediaMapper;

    @Test
    public void whenMockedSpringMapperIsUsed_thenMockedValuesAreMapped() {
        Media mockedMedia = new Media(12L, "title 12");
        when(mockMediaMapper.toEntity(ArgumentMatchers.any())).thenReturn(mockedMedia);

        MediaDto mediaDto = new MediaDto(1L, "title 1");
        Media persisted = mediaService.persistMedia(mediaDto);

        verify(mockMediaMapper).toEntity(mediaDto);
        assertEquals(mockedMedia.getId(), persisted.getId());
        assertEquals(mockedMedia.getTitle(), persisted.getTitle());
    }
}

⚠️ 对比普通测试:Spring 版本更简洁,容器自动管理 Bean 初始化。

5. 使用生成映射器的测试

替代方案:直接使用 MapStruct 生成的映射器实例。通过 Mappers 工厂类获取实例:

@Test
public void whenGeneratedMapperIsUsed_thenActualValuesAreMapped() {
    MediaService mediaService = new MediaService(Mappers.getMapper(MediaMapper.class));
    MediaDto mediaDto = new MediaDto(1L, "title 1");

    Media persisted = mediaService.persistMedia(mediaDto);

    assertEquals(mediaDto.getId(), persisted.getId());
    assertEquals(mediaDto.getTitle(), persisted.getTitle());
}

验证核心:检查返回对象属性与输入 DTO 一致。

Spring 环境需调整上下文配置,确保容器能注入生成映射器:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { Config.class, MediaSpringMapperImpl.class })
public class MediaServiceSpringGeneratedMapperTest {

最终测试用例:

@Test
public void whenGeneratedSpringMapperIsUsed_thenActualValuesAreMapped() {
    MediaDto mediaDto = new MediaDto(1L, "title 1");

    Media persisted = mediaSpringService.persistMedia(mediaDto);

    assertEquals(mediaDto.getId(), persisted.getId());
    assertEquals(mediaDto.getTitle(), persisted.getTitle());
}

✅ 验证逻辑与非 Spring 版本完全一致,底层映射器实现相同。

6. 总结

本文通过实际案例演示了测试 MapStruct 映射器依赖类的两种方法:

  1. Mock 映射器:隔离依赖,专注业务逻辑验证
  2. 生成映射器:验证真实映射行为,适合集成测试

两种方案在 Spring 和非 Spring 环境下均有对应实现,开发者可根据测试需求灵活选择。

完整示例代码见 GitHub 仓库


原始标题:How to Unit Test MapStruct Generated Mappers | Baeldung