简体   繁体   English

JUnit 测试。 使用ModelMapper库将entity转换为DTO时的问题

[英]JUnit test. The problem when converting entity to DTO by using ModelMapper library

I am working on the Spring Boot web app and I have a custom realization of the ModelMapper library that allows me to convert single objects and a list of objects.我正在开发 Spring Boot Web 应用程序,并且我有一个 ModelMapper 库的自定义实现,它允许我转换单个对象和对象列表。

@Component
public class ObjectMapperUtils {

@Autowired
private static ModelMapper modelMapper;

static {
    modelMapper = new ModelMapper();
    modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
}

private ObjectMapperUtils() {
}

public <D, T> D map(final T entity, Class<D> outClass) {
    return modelMapper.map(entity, outClass);
}

public <D, T> List<D> mapAll(final Collection<T> entityList, Class<D> outCLass) {
    return entityList.stream().map(entity -> map(entity, outCLass)).collect(Collectors.toList());
}
}

On the Service layer, I have a method returns from DB UserEntity object and convert it to UserDTO.在服务层,我有一个方法从 DB UserEntity 对象返回并将其转换为 UserDTO。

@Autowired
private UserRepository userRepository;

@Autowired
private ObjectMapperUtils modelMapper;

@Override
public UserDTO getByUserId(String userId) {
    UserEntity userEntity = userRepository.findByUserId(userId)
            .orElseThrow(() -> new NotFoundException("User with userId[" + userId + "] not found"));
    //UserDTO userDTO = new UserDTO();
    //BeanUtils.copyProperties(userEntity, userDTO);
    return modelMapper.map(userEntity, UserDTO.class); // userDTO;
}

The problem occurs when I try to create a test for this method.当我尝试为此方法创建测试时会出现问题。 UserDTO always returned as NULL value. UserDTO 始终作为 NULL 值返回。

class UserServiceImplTest {

@InjectMocks
private UserServiceImpl userService;

@Mock
private UserRepository userRepository;

@Mock
private ObjectMapperUtils modelMapper;

@BeforeEach
void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
}

@Test
void testGetByUserId() {
    UserEntity userEntity = new UserEntity();
    userEntity.setId(1L);
    userEntity.setUsername("zavada");
    userEntity.setUserId("33b4c069-e907-45a9-8d49-2042044c56e0");

    when(userRepository.findByUserId(anyString()))
                 .thenReturn(Optional.of(userEntity));

    UserDTO userDTO = userService.getByUserId("33b4c069-e907-45a9-8d49-2042044c56e0");
    System.out.println(userDTO); <--- NULL

    assertEquals("zavada", userDTO.getUsername());
    assertNotNull(userDTO);

}
}

When I use on the Service layer converting by BeanUtils.copyProperties(obj1, obj2);当我在服务层使用 BeanUtils.copyProperties(obj1, obj2) 转换时; - the test is passed successfully. - 测试成功通过。 With ModelMapper I get NULL.使用 ModelMapper 我得到 NULL。 Any ideas how to solve this error or refactor code?任何想法如何解决此错误或重构代码? Thanks in advance提前致谢

If you have a @Mock private ObjectMapperUtils modelMapper; 如果您有@Mock private ObjectMapperUtils modelMapper; then by default you do not have a real ObjectMapperUtils . 那么默认情况下,您没有真正的ObjectMapperUtils So you are not calling your implementation, you are calling the default stubs that Mockito provides for you. 因此,您不是在调用实现,而是在调用Mockito为您提供的默认存根。 That is why you are getting a null return value from modelMapper.map() . 这就是为什么您从modelMapper.map()获得null返回值的modelMapper.map()

Either do not mock the ObjectMapperUtils bean or arrange for it to do something suitable using when() etc. from the Mockito API. 要么不模拟ObjectMapperUtils bean,要么使用Mockito API中的when()等安排它进行适当的处​​理。

To build upon user268396 answer you would need the following to get this to work: 要建立在user268396答案的基础上,您需要执行以下操作才能使其工作:

@RunWith(MockitoJUnitRunner.class)
    public class StackOverflowTest {

        @InjectMocks
        private StackOverflow userService = new StackOverflow();

        @Mock
        private UserRepository userRepository;

        @Mock
        private ObjectMapperUtils modelMapper;
        private UserDTO userDTO = new UserDTO();
        private UserEntity userEntity = new UserEntity();

        @Before
        public void setUp() {
            when(modelMapper.map(any(), any())).thenReturn(userDTO);

            userDTO.setId(1L);
            userDTO.setUsername("zavada");
            userDTO.setUserId("33b4c069-e907-45a9-8d49-2042044c56e0");
        }

        @Test
        public void testGetByUserId() throws Throwable {
            when(userRepository.findByUserId(anyString())).thenReturn(Optional.of(userEntity));

            UserDTO result = userService.getByUserId("33b4c069-e907-45a9-8d49-2042044c56e0");
            System.out.println(result);

            assertEquals("zavada", result.getUsername());
            assertNotNull(result);

        }
    }

This is quite an easy mistake to make, it is important to remember that all you @mock ed objects are not real implementations anymore and if you expect any behaviour back you would need to define it upfront. 这是一个很容易犯的错误,重要的是要记住,所有@mock ed对象不再是真正的实现,并且如果您期望任何行为都需要预先定义。

For the same situation, you could also do对于同样的情况,你也可以这样做

  1. Do not mock the ObjectMapperUtils class in your test class.不要在测试类中模拟 ObjectMapperUtils 类。
  2. In the @Before init() ..{} method instantiate your UserServiceImpl to new instance of ObjectMapperUtils.在@Before init() ..{} 方法中,将您的 UserServiceImpl 实例化为 ObjectMapperUtils 的新实例。 And then set it in the UserServiceImpl.然后在 UserServiceImpl 中进行设置。 ie , userServiceImpl.setMapper(UserServiceImpl).即,userServiceImpl.setMapper(UserServiceImpl)。

So your setup method will look something like this ,所以你的设置方法看起来像这样,

@InjectMocks
private UserServiceImple userServiceImpl;

@Mock
private UserRepository userRepository;

private ObjectMapperUtil objectMapperUitl; // not mocked

@BeforeEach
public void init() { 
    objectMapperUitls = new ObjectMapperUtils();
    userServiceImple.setMapper(objectMapperUitls);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM