Unit testing with Spring Security Unit testing with Spring Security spring spring

Unit testing with Spring Security


Just do it the usual way and then insert it using SecurityContextHolder.setContext() in your test class, for example:

Controller:

Authentication a = SecurityContextHolder.getContext().getAuthentication();

Test:

Authentication authentication = Mockito.mock(Authentication.class);// Mockito.whens() for your authorization objectSecurityContext securityContext = Mockito.mock(SecurityContext.class);Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);SecurityContextHolder.setContext(securityContext);


The problem is that Spring Security does not make the Authentication object available as a bean in the container, so there is no way to easily inject or autowire it out of the box.

Before we started to use Spring Security, we would create a session-scoped bean in the container to store the Principal, inject this into an "AuthenticationService" (singleton) and then inject this bean into other services that needed knowledge of the current Principal.

If you are implementing your own authentication service, you could basically do the same thing: create a session-scoped bean with a "principal" property, inject this into your authentication service, have the auth service set the property on successful auth, and then make the auth service available to other beans as you need it.

I wouldn't feel too bad about using SecurityContextHolder. though. I know that it's a static / Singleton and that Spring discourages using such things but their implementation takes care to behave appropriately depending on the environment: session-scoped in a Servlet container, thread-scoped in a JUnit test, etc. The real limiting factor of a Singleton is when it provides an implementation that is inflexible to different environments.


Without answering the question about how to create and inject Authentication objects, Spring Security 4.0 provides some welcome alternatives when it comes to testing. The @WithMockUser annotation enables the developer to specify a mock user (with optional authorities, username, password and roles) in a neat way:

@Test@WithMockUser(username = "admin", authorities = { "ADMIN", "USER" })public void getMessageWithMockUserCustomAuthorities() {    String message = messageService.getMessage();    ...}

There is also the option to use @WithUserDetails to emulate a UserDetails returned from the UserDetailsService, e.g.

@Test@WithUserDetails("customUsername")public void getMessageWithUserDetailsCustomUsername() {    String message = messageService.getMessage();    ...}

More details can be found in the @WithMockUser and the @WithUserDetails chapters in the Spring Security reference docs (from which the above examples were copied)