java - Spring MVC - 使用 @WebMvcTest 测试 Controller 时出现 @EnableGlobalMethodSecurity 错误 404

标签 java unit-testing spring-mvc-test springmockito jsr250

我们正在尝试向 Spring 项目 Controllers 添加单元测试(顺便说一句,集成测试工作正常),但是当我们使用 添加配置时,我们遇到了非常奇怪的行为@EnableGlobalMethodSecurity (带有 JSR-250 注释)如果 Controller 实现了一个接口(interface)(无论什么接口(interface)),则 Controller 不会被 Spring 应用程序上下文包含为“请求处理程序”(我在方法中检查了它) :org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.processCandidateBean(String beanName)),即在Controler中定义的请求映射(@PostMapping,.. .) 未注册为潜在位置,但如果删除该接口(interface),则可以毫无问题地找到 Controller 和路径。

这是我的 Controller (简化版),具有简单的界面MyInterface:

@RestController
@RequestMapping(path = "/api/customer")
@RolesAllowed({Role.Const.ADMIN})
public class CustomerController implements MyInterface {    
    @Override // The only method in MyInterface 
    public void myMethod(Object param) throws QOException {
        System.out.println("Hello");
    }    
    @PostMapping(path = {"/", ""})
    public Customer create(@RequestBody Customer data) throws QOException {
        return customerService.create(data);
    }
}

这是测试类(如果我删除 @EnableGlobalMethodSecurity 配置类一切正常):

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = CustomerController.class)
@Import({ CustomerController.class, TestAuthConfiguration.class, TestAuthConfiguration2.class})  //, TestAuthConfiguration.class })
@ActiveProfiles({"test", "unittest"})
@WithMockUser(username = "test", authorities = { Role.Const.ADMIN })
class CustomerControllerTest {
    private static final Logger LOG = LogManager.getLogger(CustomerControllerTest.class);
    @EnableWebSecurity
    protected static class TestAuthConfiguration extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            LOG.info("configure(HttpSecurity http) ");
            http.csrf().disable().authorizeRequests().filterSecurityInterceptorOncePerRequest(true)
                    .antMatchers("/api/session/**").permitAll() //
                    .antMatchers("/api/**").authenticated() //
                    .anyRequest().permitAll().and() //
                    .addFilterBefore(new OncePerRequestFilter() {
                        @Override
                        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                FilterChain filterChain) throws ServletException, IOException {
                            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
                            if (auth != null) {
                                LOG.info("User authenticated: {}, roles: {}", auth.getName(), auth.getAuthorities());
                            }
                            filterChain.doFilter(request, response);
                        }
                    }, BasicAuthenticationFilter.class).sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        }

    }

    @EnableGlobalMethodSecurity(jsr250Enabled = true, securedEnabled = false)
    protected static class TestAuthConfiguration2 extends GlobalMethodSecurityConfiguration {
        @Bean
        public GrantedAuthorityDefaults grantedAuthorityDefaults() {
            return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
        }
    }

    @Autowired
    MockMvc mockMvc;

    @Test
    void testCreate() throws Exception {
        Customer bean = new Customer();
        bean.setName("Test company");           
        when(customerServiceMock.create(bean)).thenReturn(bean);
        mockMvc.perform(post("/api/customer") 
        .content(JsonUtils.toJSON(bean)).contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("Test company"));
    }
}

我不明白发生了什么,我试图在基于注释 JSR-250 (@RollesAllowed) 的安全 Controller 中找到单元测试的示例,但我没有找到任何有用的东西,无论如何这个问题(对我来说)听起来像是一个错误,但我不确定,所以欢迎任何帮助。

库版本:

  • Spring Boot 版本:2.2.2
  • Spring 核心:5.2.1
  • Mockito 核心:3.1.0

最佳答案

尝试将 proxyTargetClass 属性设置为 true。我遇到了类似的问题并通过添加此解决了它。

@EnableGlobalMethodSecurity(jsr250Enabled = true, proxyTargetClass = true)

此外,我建议阅读 EnableGlobalMethodSecurity 的 javadocs,尤其要注意 proxyTargetClassmode 属性。

关于java - Spring MVC - 使用 @WebMvcTest 测试 Controller 时出现 @EnableGlobalMethodSecurity 错误 404,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59348034/

相关文章:

spring - 如何使用 Spring MVC 测试避免 "Circular view path"异常

android - 对有延迟的 Rxjava 可观察对象进行单元测试

c# - 在单元测试输出目录中添加内容文件

java - 为什么与 jclouds 一起使用的 CloudWatch API getMetricStatisticsInRegion 会抛出 UndeclaredThrowableException?

java - 另一种不使用 "*"运算符将两个数字相乘的方法

java - AssertionFailedError 当输出相同时

java - 如何在 spring mvc Controller 中 junit 方法的返回类型

java - 拇指按比例小部件无响应

java - DialogFragment 中的 SharedPreferences NullPointerException