Spring Security mockMvc无法为单元测试模拟服务

mzaanser  于 2023-02-04  发布在  Spring
关注(0)|答案(1)|浏览(195)

我正在为Spring安全性和JWT验证编写一个单元测试。我想从3个基本案例开始测试:
1.当没有令牌时-〉预期401

  1. When标记但范围错误-〉预期403
    1.当标记和作用域-〉期望值为200时
    我用postman测试了我的代码,他们返回了预期的响应。在我的单元测试中,我有这样的代码:
@SpringBootTest
@ContextConfiguration(classes = SecurityConfig.class)
@AutoConfigureMockMvc
@EnableAutoConfiguration
@Import(DataImporterControllerConfig.class)
public class SecurityConfigTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void doImportExpect200() throws Exception {
        mockMvc.perform(put(URI).with(jwt().authorities(new SimpleGrantedAuthority(
                "SCOPE_data:write"))).contentType(APPLICATION_JSON_VALUE).accept(APPLICATION_JSON)
                        .content(BODY)).andExpect(status().isOk());
    }

它确实通过了验证部分,并尝试从控制器返回一些值:

@RestController
@RequestMapping(value = "${data.uriPrefix}")
@Loggable(value = INFO, trim = false)
public class DataImporterController {

    private final DataImporterService dataImporterService;

    @PutMapping(path = "/someurl", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE)
    public dataImportResponse doImport(@RequestHeader(name = ACCEPT, required = true) final String acceptHeader,
        final @RequestBody @NotBlank String body) {
        return new DataImportResponse(dataImporterService.doImport(body));
    }

dataImporterService.doImport(body)内部的逻辑需要一些数据库操作,因此理想情况下,我希望模拟它并使其返回一些值(类似于when(dataImporterServiceMock.doImport(body)).thenReturn(something)
但是,当我尝试它的时候,它不工作,我想这是因为我没有创建一个带有模拟服务的控制器,我尝试创建一个,但是由于SecurityConfig类的配置,它不是那么容易,下面是SecurityConfig类:

@EnableWebSecurity
public class SecurityConfig {

    @Value("${auth0.audience}")
    private String audience;

    @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
    private String issuer;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        /*
        This is where we configure the security required for our endpoints and setup our app to serve as
        an OAuth2 Resource Server, using JWT validation.
        */
        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.GET, "/actuator/**").permitAll()
            .antMatchers(HttpMethod.PUT, "/dataimporter/**").hasAuthority("SCOPE_data:write")
            .anyRequest().authenticated()
            .and().cors()
            .and().oauth2ResourceServer().jwt();
        return http.build();
    }

    @Bean
    JwtDecoder jwtDecoder() {
        /*
        By default, Spring Security does not validate the "aud" claim of the token, to ensure that this token is
        indeed intended for our app. Adding our own validator is easy to do:
        */
        NimbusJwtDecoder jwtDecoder = (NimbusJwtDecoder)
                JwtDecoders.fromOidcIssuerLocation(issuer);

        OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience);
        OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
        OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);
        jwtDecoder.setJwtValidator(withAudience);
        return jwtDecoder;
    }
}

我从Auth 0得到了这个代码,只是修改了antMatcher部分。我如何测试它,使它返回200(模拟服务或其他)?

vcudknz3

vcudknz31#

您的配置仍然有风险(启用会话和禁用CSRF保护)。您真的应该考虑使用“我的”启动器,或者按照我为configuring a resource-server with just spring-boot-oauth2-resource-server编写的教程操作。
除此之外,正如在对您的另一个问题"How to write unit test for SecurityConfig for spring security"的回答中所述,对于单元测试@Controller,使用@WebMvcTest,而不是@SpringBootTest,后者用于集成测试,加载更多的配置,并示例化和自动连接实际组件(因此,速度更慢,重点更少)

@WebMvcTest(controllers = DataImporterController.class)
public class DataImporterControllerUnitTest {
    @MockBean
    DataImporterService dataImporterService;

    @Autowired
    private MockMvc mockMvc;

    @BeforeEach
    public void setUp() {
        when(dataImporterService.doImport(body)).thenReturn(something);
    }

    @Test
    void doImportExpect200() throws Exception {
        mockMvc.perform(put(URI).with(jwt().authorities(new SimpleGrantedAuthority(
                "SCOPE_data:write"))).contentType(APPLICATION_JSON_VALUE).accept(APPLICATION_JSON)
                        .content(BODY)).andExpect(status().isOk());
    }
}

如果您遵循了link I already provided,您会在主自述文件、the many samplesthe tutorials中找到它

相关问题