0

I have a problem to mock some parts regarding Spring Security in JUnit.

I tried to write a service test regarding user registration but I couldn't handle with mock part.

Here is the relevant part in register method shown below

@Service
@Transactional
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private final AuthenticationManager authenticationManager;

    private final JwtTokenProvider jwtTokenProvider;

    private final UserRepository userRepository;

    private final PasswordEncoder passwordEncoder;

    public AuthResponse register(RegisterRequest registerRequest) {
    ...

    UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(registerRequest.getUsername(), registerRequest.getPassword());
    Authentication auth = authenticationManager.authenticate(authToken);
    SecurityContextHolder.getContext().setAuthentication(auth);
    String jwtToken = jwtTokenProvider.generateJwtToken(auth);
    ...
}

Here is the test method relevant part

    @Mock
    private UserRepository userRepository;
    
    @Mock
    private JwtTokenProvider jwtTokenProvider;
    
    @Mock
    private AuthenticationManager authenticationManager;
    
    @InjectMocks
    private AuthServiceImpl authService;
    
    @Mock
    private PasswordEncoder passwordEncoder;
    
    @Mock
    private SecurityContext securityContext;

    @Mock
    private Authentication authentication;

    @Test
    public void shouldRegister() {

    // when
    when(userRepository.save(any(User.class))).thenReturn(user);
            
    when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class)))
                    .thenReturn(new UsernamePasswordAuthenticationToken(registerRequest.getUsername(), registerRequest.getPassword()));
            when(SecurityContextHolder.getContext()).thenReturn(securityContext);
    when(securityContext.getAuthentication()).thenReturn(authentication);
            
when(jwtTokenProvider.generateJwtToken(any(Authentication.class))).thenReturn("test_token");
}

Here is the issue shown below.

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Here is spring security test dependency defined in pom.xml

<dependency>
     <groupId>org.springframework.security</groupId>
     <artifactId>spring-security-test</artifactId>
     <scope>test</scope>
</dependency>
S.N
  • 2,157
  • 3
  • 29
  • 78
  • You should be using an integration test to check spring security. Check https://stackoverflow.com/questions/15203485/spring-test-security-how-to-mock-authentication – Dhaval Gajjar Mar 11 '23 at 16:58
  • @DhavalGajjar I try to write service as you can see. Could you tell me how to fix it? – S.N Mar 11 '23 at 17:01
  • Also in the register method, you are creating `Authentication` class object. Then you set that to `SecurityContextHolder`. Why you are mocking that you already set those so in the register test case as per the code you have given you need to validate whether it's set or not. – Dhaval Gajjar Mar 11 '23 at 18:16

1 Answers1

0

The exception you are getting is that you are not mocking a mock. SecurityContextHolder.getContext().getAuthentication() is not a mock, mockito is unable to mock its behavour.

@DhavalGajjar pointed you to an answere that will help you create a test for spring security. Mockito will be hard to get working for spring security, which is why there is a spring-security-test module avaialble to assist in creating it, examples are in @DhavalGajjar's link

user2131323
  • 105
  • 10