1

I have a spring boot application and want to write integration tests for controllers. It is my SecurityConfig:

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final MyUserDetailsService userDetailsService;
    private final SessionAuthenticationProvider authenticationProvider;
    private final SessionAuthenticationFilter sessionAuthenticationFilter;

    @Override
    public void configure(WebSecurity web) {
        //...
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
     /... 
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
        auth.userDetailsService(userDetailsService);
    } 
}

It is my controller:

@RestController
public class MyController {

    //...

    @GetMapping("/test")
    public List<TestDto> getAll(){
        List<TestDto> tests= testService.findAll(authService.getLoggedUser().getId());
        return mapper.toTestDtos(tests);
    }
}

I Created a test(JUnit 5):

@WebMvcTest(TestController.class)
class TestControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean(name = "mockTestService")
    private TestService testService;

    @Autowired
    private TestMapper mapper;

    @MockBean(name = "mockAuthService")
    private AuthService authService;

    private Test test;

    @BeforeEach
    void setUp() {
        User user = new Test();
        user.setId("userId");
        when(authService.getLoggedUser()).thenReturn(user);
        test = new Facility();
        test.setId("id");
        test.setName("name");
        when(testService.findAll("userId")).thenReturn(singletonList(test));
    }

    @Test
    void shouldReturnAllIpaFacilitiesForCurrentTenant() throws Exception {
        mockMvc.perform(get("/test").contentType(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$..id").value(test.getId()))
                .andExpect(jsonPath("$..timeOut").value(test.getName()));
    }
}

When I start the test I get an exception: Consider defining a bean of type 'com.auth.MyUserDetailsService' in your configuration.

It happens because I have not UserDetailsService bean in the test. What should I do:

  1. Add 3 beans are required for SecurityConfig, like:

    @MockBean MyUserDetailsService userDetailsService; @MockBean SessionAuthenticationProvider authenticationProvider; @MockBean SessionAuthenticationFilter sessionAuthenticationFilter;

  2. Add test implementation of SecurityConfig

  3. something else

Which approach is better?

Pavel Petrashov
  • 1,073
  • 1
  • 15
  • 34

1 Answers1

0

For writing tests for your controller endpoints using @WebMvcTest I would use the great integration from MockMvc and Spring Security.

Make sure you have the following dependency:

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-test</artifactId>
  <scope>test</scope>
</dependency>

Next, you can mock the authenticated user for your MockMvc requests and also set the username, roles, etc.

Either use an annotation to populate the authenticated user inside the SecurityContext for the test:

@Test
@WithMockUser("youruser")
public void shouldReturnAllIpaFacilitiesForCurrentTenant() throws Exception {
   // ... 
}

Or use one of the SecurityMockMvcRequestPostProcessors:

this.mockMvc
  .perform(
      post("/api/tasks")
        .contentType(MediaType.APPLICATION_JSON)
        .content("{\"taskTitle\": \"Learn MockMvc\"}")
        .with(csrf())
        .with(SecurityMockMvcRequestPostProcessors.user("duke"))
    )
  .andExpect(status().isCreated());

You can find more information on this here.

rieckpil
  • 10,470
  • 3
  • 32
  • 56
  • I can not start my test, because I get an exception: Consider defining a bean of type 'com.auth.MyUserDetailsService' in your configuration. I wrote it in my question. When I start the integration test it tries to start SecurityConfig and SecurityConfig requires MyUserDetailsService and 2 more beans – Pavel Petrashov Oct 28 '20 at 10:32