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 映射器接口
基于 MediaDto 和 Media 定义映射器接口:
@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 映射器依赖类的两种方法:
- Mock 映射器:隔离依赖,专注业务逻辑验证
- 生成映射器:验证真实映射行为,适合集成测试
两种方案在 Spring 和非 Spring 环境下均有对应实现,开发者可根据测试需求灵活选择。
完整示例代码见 GitHub 仓库