首页 > 解决方案 > 使用 JUnit5+Spring Security 测试 Spring Boot 控制器

问题描述

我有一个 Spring Boot 应用程序,想为控制器编写集成测试。这是我的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);
    } 
}

这是我的控制器:

@RestController
public class MyController {

    //...

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

我创建了一个测试(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()));
    }
}

当我开始测试时,出现异常:Consider defining a bean of type 'com.auth.MyUserDetailsService' in your configuration.

发生这种情况是因为我在测试中没有 UserDetailsS​​ervice bean。我应该怎么办:

  1. SecurityConfig 需要添加 3 个 bean,例如:

    @MockBean MyUserDetailsS​​ervice userDetailsS​​ervice; @MockBean SessionAuthenticationProvider 身份验证提供者;@MockBean SessionAuthenticationFilter sessionAuthenticationFilter;

  2. 添加 SecurityConfig 的测试实现

  3. 别的东西

哪种方法更好?

标签: spring-bootspring-securityjunit5spring-boot-testspring-security-rest

解决方案


为了使用Spring Security为您的控制器端点编写测试,@WebMvcTest我将使用出色的集成。MockMvc

确保您具有以下依赖项:

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

接下来,您可以为您的MockMvc请求模拟经过身份验证的用户,并设置用户名、角色等。

使用注释SecurityContext在测试中填充经过身份验证的用户:

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

或使用以下之一SecurityMockMvcRequestPostProcessors

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

您可以在此处找到更多信息。


推荐阅读