Run unit tests on controllers requiring authentication

I have a spring boot application that requires login for some action. I am trying to test them using MockMvc , but it does not seem to work. I keep getting an HTTP response with a status of 403 (forbidden). Maybe something is wrong with the authentication part.

I tried following the documentation , but I could not get it to work.

This is my current test code:

 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = {Application.class}) @WebIntegrationTest("server.port = 8093") public class PasswordChangeTests { @Autowired private EmbeddedWebApplicationContext webApplicationContext; @Autowired private UserRepository userRepository; private MockMvc mockMvc; @Before public void setUp() throws Exception { this.mockMvc = MockMvcBuilders .webAppContextSetup(webApplicationContext) .apply(springSecurity()) .build(); } @Test public void changePasswordWorks() throws Exception { // Send password change request PasswordChangeRepresentation passwordChange = new PasswordChangeRepresentation(DefaultUsers.Admin.getPassword(), "12345678"); mockMvc.perform(MockMvcRequestBuilders.request(HttpMethod.POST, "/password/change") .content(new ObjectMapper().writeValueAsString(passwordChange)) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); // Check that the password has been changed User user = this.userRepository.findByUsername(DefaultUsers.Admin.getEmail()); Assert.assertEquals(user.getPassword(), "12345678"); } } 

Sorry if I am missing something obvious. This is my first spring boot experience.

+7
java spring-boot spring-mvc spring-security mockmvc
source share
1 answer

You need to specify which user you want to run the test with. You have several options (each option is a link to detailed documentation):

@WithMockUser

This option will create a fake user (that is, the user should not exist in the data warehouse). The problem with this approach is that if your application depends on the user's user implementation, you may get class exceptions. If you are not returning a native type from a custom UserDetailsService, this solution should work fine.

  @Test @WithMockUser(username="admin",roles={"USER","ADMIN"}) public void changePasswordWorks() throws Exception { 

@WithUserDetails

If you have implemented a custom UserDetailsService that returns a custom implementation of UserDetails, this solution may work for you.

For it to work, you need to set the UserDetailsService as a Bean, and the user must exist. For example:

  @Test @WithUserDetails("admin") public void changePasswordWorks() throws Exception { 

@WithSecurityContext

This is the best of both worlds, but requires a bit of customization. If you have a custom UserDetailsService that returns a custom implementation of UserDetails and DOES NOT want the user to exist, you can use this method. I will let you read the documentation for this setting as it is a little longer and well documented.

Using RequestPostProcessor

If annotations are not your thing, you can use RequestPostProcessor. For example:

 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; ... @Test public void changePasswordWorks() throws Exception { // Send password change request PasswordChangeRepresentation passwordChange = new PasswordChangeRepresentation(DefaultUsers.Admin.getPassword(), "12345678"); mockMvc.perform(MockMvcRequestBuilders.request(HttpMethod.POST, "/password/change") // ADD this line .with(user("admin").roles("USER","ADMIN")) .content(new ObjectMapper().writeValueAsString(passwordChange)) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); // Check that the password has been changed User user = this.userRepository.findByUsername(DefaultUsers.Admin.getEmail()); Assert.assertEquals(user.getPassword(), "12345678"); } 
+21
source share

All Articles