如何在 JUnit5 中模拟 MapStruct 嵌套映射器

问题描述 投票:0回答:4

我已经寻找解决方案大约一天了。我仍然无法生成一个有效的示例。

我的问题很简单。我有一个映射器使用另一个映射器:

@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 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 UserMapperImpl:

这涉及到我的基本问题,如何模拟或自动装配嵌套映射器类?

java junit5 mapstruct
4个回答
8
投票

嵌套映射器为空,因为 Spring 上下文未加载。因此,@Autowired 不起作用。

解决方案是通过 ReflectionTestUtils 注入嵌套映射器。

@InjectMocks
private UserMapper mapper = UserMapperImpl.INSTANCE;

@Before
public void init() {
    RoleMapper roleMapper = Mappers.getMapper(RoleMapper.class);
    ReflectionTestUtils.setField(mapper, "roleMapper", roleMapper);
}

3
投票

正如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() {
        ...
    }
}

0
投票

我不知道你的应用程序的生态系统,但如果你使用 Spring Boot,你可以将测试类 UserMapperTest 标记为

@SpringBootTest
并将你的映射器自动装配为常规 bean

    @Autowired
    private UserMapper mapper;

0
投票

对于没有模拟的单元测试,您可以使用

injectionStrategy = InjectionStrategy.CONSTRUCTOR
例如

@Mapper(
        componentModel = MappingConstants.ComponentModel.SPRING,
        uses = {RoleMapper.class},
        injectionStrategy = InjectionStrategy.CONSTRUCTOR
)
public interface UserMapper {

然后,您可以使用生成的完整参数构造函数在测试中启动 UserMapper,如下所示

private final UserMapper userMapper = new UserMapper Impl(new RoleMapperImpl());

无需注入Mocks,也无需上下文。

© www.soinside.com 2019 - 2024. All rights reserved.