0

i am using PowerMockRunner in a spring-boot application for testing. Everything is working but when my controllers actions definition contain someControllerMethod(..., Authentication auth, ...). Then auth is null and therefore some code is not working.

What i tried is to mock Authentication and SecurityContext. Came up with something like this

    private void mockSecurity() {
        Authentication authentication = mock(Authentication.class);
        SecurityContext securityContext = mock(SecurityContext.class);

        List<SimpleGrantedAuthority> authorities = Arrays.asList(new SimpleGrantedAuthority("USER"));
        User mockedUser = new User("testuser", "passwordtest", authorities);

        when(securityContext.getAuthentication()).thenReturn(authentication);
        SecurityContextHolder.setContext(securityContext);
        when(SecurityContextHolder.getContext().getAuthentication().getDetails()).thenReturn(mockedUser);
        when(SecurityContextHolder.getContext().getAuthentication().getName()).thenReturn(mockedUser.getUsername());
    }

Now those mocks work, if my code uses SecurityContextHolder.getContext().getAuthentication() method of accessing the authentication, but not for the one automatically injected (probably because it is not yet mocked when the controller mock is created).

Any ideas how to mock the injected Authentication so the code does not need to be changed? spring-security-testand @MockWithUser have the same result.

Relevant parts of the test look like this,

@RunWith(PowerMockRunner.class)
public class UserControllerTest {
    @InjectMocks
    UserController userController;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mockMvc = standaloneSetup(userController).build();
    }

    @Test
    public void getUserDetails() {
        mockSecurity();
        mockMvc.perform(...).andExpect(...);
    }
}

Edit as requested by pvpkiran the controller code

@RequestMapping(...)
public void getDetails(@PathVariable String id, Authentication auth) {
    UserDetails loadedDetails = userService.getUserDetails(id);
    if (!loadedDetails.getUserId().equals(auth.getName())) {
         throw new Exception(...);
    }
    ...
}
patman
  • 2,780
  • 4
  • 30
  • 54
  • show your controller class/method where you have this Authentication used. Without that it is hard to comment – pvpkiran Jan 03 '19 at 10:19
  • Edited. But i think the core problem has nothing to do with the controller code per se. Simply the injected `Authentication` is null and shouldn't, rather it should be mocked. – patman Jan 03 '19 at 10:26
  • checkt this out https://techdev.io/en/developer-blog/testing-a-secured-spring-data-rest-service-with-java-8-and-mockmvc – pvpkiran Jan 03 '19 at 10:35
  • Thank you but it uses a different test runner and a different test configuration. So for me that is not applicable. – patman Jan 03 '19 at 11:39
  • you are missing the point. But the idea is similar. Doesn't matter which runner u r using. Main thing is `mockMvc.perform( get("/employees") .session(..)` – pvpkiran Jan 03 '19 at 13:23

0 Answers0