JUnit测试中Mockito模拟对象为null的问题求助
Mockito单元测试返回Null的问题排查与解决
问题场景
使用JUnit 5 + Mockito编写UserService的单元测试时,所有测试均返回null,断言失败。以下是相关代码及错误信息:
测试类代码
@ExtendWith(MockitoExtension.class) class UserServiceTest { @InjectMocks private UserService userService; @Mock private UserDAO userDAO; @Mock private ModelMapper modelMapper; @Mock private UserDTOMapper userDTOMapper; private User user; private UserDTO userDTO; private AutoCloseable closeable; @BeforeTestMethod public void initMocks(){ MockitoAnnotations.openMocks(this); } @BeforeEach void setUp() { userDTO = UserDTO.builder() .username("johnny") .firstname("John") .surname("Rogers") .email("john@gmail.com") .phoneNumber("0123456789") .role(Role.ADMIN).build(); user = User.builder() .username("johnny") .password("johnny123") .firstname("John") .surname("Rogers") .email("john@gmail.com") .phoneNumber("0123456789") .role(Role.ADMIN).build(); } @Test void findUser() { userDao.sace(user); assertEquals(userDTO, userService.findUser(user.getUsername())); } @Test void convertToDto() { assertEquals(userDTO, userDTOMapper.apply(user)); } @AfterTestMethod public void releaseMocks() throws Exception { closeable.close(); } }
服务类代码
@Service @RequiredArgsConstructor public class UserService { private final UserDAO userDAO; private final ModelMapper modelMapper; private final UserDTOMapper userDTOMapper; public UserDTO findUser(String username) { User user = userDAO.findUserByUsername(username); return userDTOMapper.apply(user); } public UserDTO convertToDto(User user) { return modelMapper.map(user, UserDTO.class); } }
错误信息
org.opentest4j.AssertionFailedError: Expected :UserDTO(id=0, username=johnny, firstname=John, surname=Rogers, email=john@gmail.com, phoneNumber=0123456789, role=USER) Actual :null <Click to see difference> at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151) at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132) at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197) at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182) at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177) at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1142)
问题分析与修正
核心问题点
- Mock初始化冗余且错误:已经使用
@ExtendWith(MockitoExtension.class),无需手动调用MockitoAnnotations.openMocks(this),且closeable未赋值会导致资源释放报错,同时干扰Mock对象的正确注入。 - 未Stub Mock方法:Mockito的Mock对象默认返回
null,测试中未对依赖的DAO、Mapper方法设置返回值,导致服务方法调用后返回null。 - 测试逻辑错误:
findUser测试中调用userDao.sace(user)是拼写错误(应为save),且该调用对服务方法的逻辑无意义,服务类的findUser依赖的是findUserByUsername方法。 - JUnit注解混用:
@BeforeTestMethod和@AfterTestMethod是JUnit 4的注解,JUnit 5应使用@BeforeEach和@AfterEach。
修正后的测试类代码
@ExtendWith(MockitoExtension.class) class UserServiceTest { @InjectMocks private UserService userService; @Mock private UserDAO userDAO; @Mock private ModelMapper modelMapper; @Mock private UserDTOMapper userDTOMapper; private User user; private UserDTO userDTO; @BeforeEach void setUp() { userDTO = UserDTO.builder() .username("johnny") .firstname("John") .surname("Rogers") .email("john@gmail.com") .phoneNumber("0123456789") .role(Role.ADMIN).build(); user = User.builder() .username("johnny") .password("johnny123") .firstname("John") .surname("Rogers") .email("john@gmail.com") .phoneNumber("0123456789") .role(Role.ADMIN).build(); } @Test void findUser() { // Stub DAO方法,指定调用时的返回值 when(userDAO.findUserByUsername(user.getUsername())).thenReturn(user); // Stub Mapper方法,指定转换后的返回值 when(userDTOMapper.apply(user)).thenReturn(userDTO); UserDTO result = userService.findUser(user.getUsername()); assertEquals(userDTO, result); } @Test void convertToDto() { // Stub ModelMapper的转换方法 when(modelMapper.map(user, UserDTO.class)).thenReturn(userDTO); UserDTO result = userService.convertToDto(user); assertEquals(userDTO, result); } }
修正说明
- 移除冗余的Mock初始化和资源释放代码,由
MockitoExtension自动处理Mock的生命周期。 - 为每个测试中依赖的Mock方法添加
when().thenReturn()Stub,确保调用时返回预设的对象,而非默认的null。 - 修正测试逻辑,使其与服务类的实际调用链一致,确保测试覆盖真实的业务流程。
内容的提问来源于stack exchange,提问作者caspian
相关产品推荐
相关产品推荐

