如何在 JUnit5 中模拟 MapStruct 嵌套映射器
How to mock MapStruct nested mapper in JUnit5
我已经搜索了大约一天的解决方案。我仍然无法提供一个工作示例。
我的问题很简单。我有一个映射器使用另一个映射器:
@Mapper(componentModel = "spring", uses = {RoleMapper.class})
public interface UserMapper {
/**
* Converts User DTO to User JPA Entity
* @Mapping annotation is used to convert fields with different names
* @param dto
* @return
*/
@Mappings({
@Mapping(target = "identityNo", source = "dto.userIdentity"),
@Mapping(target = "role", source = "dto.roleDTO")
})
User dtoToEntity(UserDTO dto);
/**
* Converts User JPA Entity to User DTO
* @Mapping annotation is used to convert fields with different names
* @param entity
* @return
*/
@Mappings({
@Mapping(target = "userIdentity", source = "entity.identityNo"),
@Mapping(target = "roleDTO", source = "entity.role")
})
UserDTO entityToDto(User entity);
}
@Mapper(componentModel = "spring")
public interface RoleMapper {
Role roleDtoToEntity(RoleDTO dto);
RoleDTO roleEntityToDto(Role entity);
}
我的测试 class 测试映射器是否正常工作:
class UserMapperTest {
private UserMapper mapper = Mappers.getMapper(UserMapper.class);
@Test
void dtoToEntity() {
User user = new User();
user.setName("john");
user.setSurname("doe");
user.setIdentityNo("11111111111");
user.setRole(new Role("ROLE_ADMIN"));
UserDTO dto = mapper.entityToDto(user);
Assertions.assertEquals(user.getName(), dto.getName());
Assertions.assertEquals(user.getSurname(), dto.getSurname());
Assertions.assertEquals(user.getIdentityNo(), dto.getUserIdentity());
Assertions.assertEquals(user.getRole().getName(), dto.getRoleDTO().getName());
}
}
但是在自动生成的impl中调用roleMapper的那一行抛出NullPointerException class UserMapperImpl:
这是我的基本问题,如何模拟或自动装配嵌套映射器class?
嵌套映射器为空,因为 Spring 上下文未加载。因此,@Autowired 无法正常工作。
解决方案是通过 ReflectionTestUtils 注入嵌套映射器。
@InjectMocks
private UserMapper mapper = UserMapperImpl.INSTANCE;
@Before
public void init() {
RoleMapper roleMapper = Mappers.getMapper(RoleMapper.class);
ReflectionTestUtils.setField(mapper, "roleMapper", roleMapper);
}
我不知道你的应用程序的生态系统,但如果你使用 spring 引导,你可以将测试 class UserMapperTest 标记为 @SpringBootTest
并将你的映射器作为常规 bean 自动装配
@Autowired
private UserMapper mapper;
如 Jakub Słowikowski 所述,但更花哨:
@ExtendWith(MockitoExtension.class)
class MyClassTest {
@InjectMocks
private MyService myService;
@Mock
private MyApi myApi;
@Spy
private MyMapper myMapper = Mappers.getMapper(MyMapper.class);
@Test
void myTest() {
...
}
}
我已经搜索了大约一天的解决方案。我仍然无法提供一个工作示例。
我的问题很简单。我有一个映射器使用另一个映射器:
@Mapper(componentModel = "spring", uses = {RoleMapper.class})
public interface UserMapper {
/**
* Converts User DTO to User JPA Entity
* @Mapping annotation is used to convert fields with different names
* @param dto
* @return
*/
@Mappings({
@Mapping(target = "identityNo", source = "dto.userIdentity"),
@Mapping(target = "role", source = "dto.roleDTO")
})
User dtoToEntity(UserDTO dto);
/**
* Converts User JPA Entity to User DTO
* @Mapping annotation is used to convert fields with different names
* @param entity
* @return
*/
@Mappings({
@Mapping(target = "userIdentity", source = "entity.identityNo"),
@Mapping(target = "roleDTO", source = "entity.role")
})
UserDTO entityToDto(User entity);
}
@Mapper(componentModel = "spring")
public interface RoleMapper {
Role roleDtoToEntity(RoleDTO dto);
RoleDTO roleEntityToDto(Role entity);
}
我的测试 class 测试映射器是否正常工作:
class UserMapperTest {
private UserMapper mapper = Mappers.getMapper(UserMapper.class);
@Test
void dtoToEntity() {
User user = new User();
user.setName("john");
user.setSurname("doe");
user.setIdentityNo("11111111111");
user.setRole(new Role("ROLE_ADMIN"));
UserDTO dto = mapper.entityToDto(user);
Assertions.assertEquals(user.getName(), dto.getName());
Assertions.assertEquals(user.getSurname(), dto.getSurname());
Assertions.assertEquals(user.getIdentityNo(), dto.getUserIdentity());
Assertions.assertEquals(user.getRole().getName(), dto.getRoleDTO().getName());
}
}
但是在自动生成的impl中调用roleMapper的那一行抛出NullPointerException class UserMapperImpl:
这是我的基本问题,如何模拟或自动装配嵌套映射器class?
嵌套映射器为空,因为 Spring 上下文未加载。因此,@Autowired 无法正常工作。
解决方案是通过 ReflectionTestUtils 注入嵌套映射器。
@InjectMocks
private UserMapper mapper = UserMapperImpl.INSTANCE;
@Before
public void init() {
RoleMapper roleMapper = Mappers.getMapper(RoleMapper.class);
ReflectionTestUtils.setField(mapper, "roleMapper", roleMapper);
}
我不知道你的应用程序的生态系统,但如果你使用 spring 引导,你可以将测试 class UserMapperTest 标记为 @SpringBootTest
并将你的映射器作为常规 bean 自动装配
@Autowired
private UserMapper mapper;
如 Jakub Słowikowski 所述,但更花哨:
@ExtendWith(MockitoExtension.class)
class MyClassTest {
@InjectMocks
private MyService myService;
@Mock
private MyApi myApi;
@Spy
private MyMapper myMapper = Mappers.getMapper(MyMapper.class);
@Test
void myTest() {
...
}
}