关于 unit-test-mapper-converter
面向开发者的测试技能,用于为 MapStruct 映射器和自定义转换器编写单元测试,涵盖映射准确性、空值处理、嵌套及双向转换等场景。
主要功能
- 01测试字段与类型映射
- 02检查空值处理
- 03覆盖嵌套与双向映射
- 04测试枚举和集合转换
- 05验证自定义映射表达式
适用场景
- 01测试 MapStruct 生成的映射器实现
- 02验证实体到 DTO 的转换器行为
- 03检查嵌套对象与集合映射
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill unit-test-mapper-converter安装后在 Claude Code 中输入/unit-test-mapper-converter确认已加载。
附带文件references/examples.md
详细介绍
映射器和转换器的单元测试
概述
介绍 MapStruct 映射器和自定义转换器类的单元测试模式。涵盖字段映射准确性、空值处理、类型转换、嵌套对象转换、双向映射、枚举映射和部分更新。
使用场景
- 为 MapStruct 映射器实现编写映射测试
- 测试自定义实体到 DTO 的转换器和 Bean 映射
- 验证嵌套对象映射和集合转换
说明
1. 验证生成的映射器类
测试前,确认生成的映射器类存在:
# Maven
ls target/generated-sources/
# Gradle
ls build/generated/sources/
如果缺少生成的类:
- 运行
mvn compile(Maven)或./gradlew compileJava(Gradle) - 检查是否已配置 MapStruct 注解处理器
- 确认
@Mapper接口位于已编译的源代码集中
2. 测试空值处理
assertThat(mapper.toDto(null)).isNull();
如果空值应返回空对象或默认值,请在映射器中配置 nullValueMappingStrategy。
如果空值测试失败:
- 将
nullValueMappingStrategy = NullValueMappingStrategy.RETURN_NULL添加到@Mapper - 或使用
nullValuePropertyMappingStrategy处理嵌套属性
3. 测试双向映射
User restored = mapper.toEntity(mapper.toDto(original));
assertThat(restored).usingRecursiveComparison().isEqualTo(original);
如果双向映射测试失败:
- 检查
@Mapping注解中的字段名称是否不匹配 - 如果自动映射失败,请确认已显式映射两个方向
- 使用
unmappedTargetPolicy = ReportingPolicy.ERROR捕获缺失的映射
4. 测试嵌套对象映射
assertThat(dto.getNested()).usingRecursiveComparison().isEqualTo(expected);
如果嵌套对象测试失败:
- 确保存在嵌套映射器,或通过
uses = NestedMapper.class引用它 - 使用
elementMappingStrategy检查集合元素映射
5. 测试自定义表达式
@Mapping(target = "field", expression = "java(...)") 中的自定义表达式不会在编译时验证。
如果表达式测试失败:
- 检查表达式语法和方法签名
- 确认表达式上下文可以访问导入的类
6. 测试枚举映射
使用 @ValueMapping 转换枚举。全面测试所有枚举值。
最佳实践
- 独立测试使用
Mappers.getMapper(),集成测试使用 Spring 注入 - 对复杂嵌套结构使用
usingRecursiveComparison() - 测试所有映射器方法,包括集合转换
- 验证所有可空源字段的空值处理
- 测试双向映射,以捕获实体→DTO 和 DTO→实体之间的不对称
- 让映射器测试聚焦于转换正确性,而非实现细节
限制和警告
- 编译时生成:MapStruct 在编译时生成代码;运行测试前请确认生成的类存在
- 空值处理:适当配置
nullValueMappingStrategy和nullValuePropertyMappingStrategy - 表达式验证:
@Mapping中的表达式不会在编译时验证,请显式测试 - 循环依赖:MapStruct 无法处理映射器之间的循环依赖
- 集合不可变性:映射不可变集合可能需要特殊配置
- 日期/时间:验证日期/时间对象在不同时区之间是否能正确映射
示例
包含导入语句的完整可执行测试:
package com.example.mapper;
import org.junit.jupiter.api.Test;
import org.mapstruct.factory.Mappers;
import static org.assertj.core.api.Assertions.*;
class UserMapperCompleteTest {
private final UserMapper mapper = Mappers.getMapper(UserMapper.class);
@Test
void shouldMapUserToDto() {
User user = new User(1L, "Alice", "[email protected]", 25);
UserDto dto = mapper.toDto(user);
assertThat(dto)
.isNotNull()
.extracting(UserDto::getName, UserDto::getEmail)
.containsExactly("Alice", "[email protected]");
}
@Test
void shouldMaintainRoundTrip() {
User original = new User(1L, "Alice", "[email protected]", 25);
assertThat(mapper.toEntity(mapper.toDto(original)))
.usingRecursiveComparison()
.isEqualTo(original);
}
@Test
void shouldHandleNullInput() {
assertThat(mapper.toDto(null)).isNull();
}
}
更多示例见:references/examples.md
评论
支持 Markdown