首页 > 解决方案 > JUNIT5 @InjectMocks 抛出 NullPointerException

问题描述

这是我第一个使用 TDD 和 JUNIT 5 的项目。我正在为我的项目使用最新的 Springboot。

我注意到,当我有来自 springboot 的依赖项时,在使用 @InjectMocks 注释时,它们不会在测试阶段被注入。我正在为 authenticationManager 依赖项获取 NullPointerException。但是,当服务方法仅使用使用 springboot JPA 为实体类创建的存储库依赖项时,测试通过。

下面是服务类和对应的测试类。 UserServiceImpl.java

@Service
public class UserServiceImpl implements UserService {

@Autowired
AuthenticationManager authenticationManager;

@Autowired
UserRepository userRepository;

@Autowired
PasswordEncoder passwordEncoder;

@Autowired
UserDetailsService userDetailsService;

@Autowired
JWTUtil jwtUtil;

@Override
@Transactional
public AuthenticationResponseDTO login(AuthenticationRequestDTO authenticationRequestDTO) {
    try {
        authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(authenticationRequestDTO.getUserName(), authenticationRequestDTO.getPassword()));

        UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequestDTO.getUserName());

        return new AuthenticationResponseDTO(userDetails.getUsername(), jwtUtil.generateToken(userDetails));
    }
    catch (BadCredentialsException e) {
        throw e;
    }
}

UserServiceImplTest.java

@InjectMocks
private UserServiceImpl userServiceImpl;

@Mock
private UserRepository userRepository;

private User userMock;

private AuthenticationRequestDTO authenticationRequestDTO;

@BeforeEach
void init(){
    MockitoAnnotations.initMocks(this);
}

@BeforeEach
void setupUser(){
    userMock = new User();
    userMock.setUserName("sd");
    userMock.setPassword("sd");

    authenticationRequestDTO = new AuthenticationRequestDTO();
    authenticationRequestDTO.setUserName("sd");
    authenticationRequestDTO.setPassword("sd");
}

@Test
void testUserIsPresentOrNot(){

    Mockito.when( userRepository.findByUserName("sd") ).thenReturn(userMock);

    AuthenticationResponseDTO responseDTO = userServiceImpl.login(authenticationRequestDTO);

    assertNotNull(responseDTO);
    assertEquals(userMock.getUserName(), responseDTO.getName(), "user id should be same.");
}

如果我需要进一步的细节,请告诉我。

标签: spring-bootspring-securitytddjunit5

解决方案


我不确定我是否 100% 关注,因为我可以看到您缺少一些注释。

如果你想在你需要的单元测试中注入 Spring bean @SpringBootTest/@ExtendWith(SpringExtension.class)(从我的角度来看它是集成测试)。

如果您想使用 Mockito @InjectMocks@Mock要求@ExtendWith(MockitoExtension.class)高于测试类。

并删除以下内容。

@BeforeEach
void init(){
    MockitoAnnotations.initMocks(this);
}

从我的角度来看,将依赖注入与 spring 和 Mockito 混合起来太复杂了。我宁愿只使用 Mockito 进行单元测试。

也许下面的文章可以提供帮助。


推荐阅读