使用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 authenticationProvider; @MockBean SessionAuthenticationFilter sessionAuthenticationFilter;

  2. 添加SecurityConfig的测试实现

  3. 其他东西

哪种方法更好?

解决方法

要使用@WebMvcTest为您的控制器端点编写测试,我将使用MockMvc和Spring Security的强大集成。

确保您具有以下依赖性:

<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());

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...