java.lang.Исключение IllegalStateException(Метод не найден): Вызов MockMvc.выполните несколько раз в одном тесте с настраиваемым фильтром

#spring #spring-boot #kotlin #spring-security #spring-test

Вопрос:

Для извлечения UserDetails объекта в spring security protected REST api с @AuthenticationPrincipal аннотацией я добавляю в MockMvc объект настраиваемый фильтр, что-то вроде:

 @ExtendWith(SpringExtension::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class BaseSpringIntegrationTest {
    @Autowired
    private lateinit var context: WebApplicationContext

    lateinit var mockMvc: MockMvc

    val mockUser = UsernamePasswordAuthenticationToken(MyUserDetails("MOCK_USER"), "MOCK_PASSWORD",  listOf(SimpleGrantedAuthority("MOCKED_ROLE")))

    @PostConstruct
    fun init() {
        mockMvc = MockMvcBuilders
            .webAppContextSetup(context)
            .apply<DefaultMockMvcBuilder>(springSecurity(mockSpringSecurityFilter))
            .build()
    }

    private val mockSpringSecurityFilter = object: Filter {
        override fun doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain) {
            with ((req as HttpServletRequest).userPrincipal) {
                if (this != null)
                    SecurityContextHolder.getContext().authentication = this as Authentication
                }
            chain.doFilter(req, res)
        }

        override fun destroy() {
            SecurityContextHolder.clearContext()
        }
    }
}
 

А затем я пытаюсь mockMvc дважды вызвать объект в некотором тесте следующим образом:

 class DummyTests: BaseSpringIntegrationTest() {
    @Test
    fun dummyTest() {
        mockMvc.perform(MockMvcRequestBuilders.post("<MY_URL>").principal(mockUser))
            .andExpect(MockMvcResultMatchers.status().`is`(HttpStatus.OK.value()))

        mockMvc.perform(MockMvcRequestBuilders.post("<ANOTHER_URL>").principal(mockUser))
            .andExpect(MockMvcResultMatchers.status().`is`(HttpStatus.OK.value()))
    }
}
 

При запуске теста java.IllegalStateException выбрасывается второй perform лайк:

 Method not found: BaseSpringIntegrationTest$mockSpringSecurityFilter$1.getFilters(org.springframework.mock.web.MockHttpServletRequest)
java.lang.IllegalStateException: Method not found: BaseSpringIntegrationTest$mockSpringSecurityFilter$1.getFilters(org.springframework.mock.web.MockHttpServletRequest)
    at org.springframework.util.ReflectionUtils.handleReflectionException(ReflectionUtils.java:104)
    at org.springframework.test.util.ReflectionTestUtils.invokeMethod(ReflectionTestUtils.java:502)
    at org.springframework.test.util.ReflectionTestUtils.invokeMethod(ReflectionTestUtils.java:427)
    at org.springframework.security.test.web.support.WebTestUtils.findFilter(WebTestUtils.java:121)
    at org.springframework.security.test.web.support.WebTestUtils.getSecurityContextRepository(WebTestUtils.java:63)
    at org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors$SecurityContextRequestPostProcessorSupport.save(SecurityMockMvcRequestPostProcessors.java:725)
    at org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors$TestSecurityContextHolderPostProcessor.postProcessRequest(SecurityMockMvcRequestPostProcessors.java:805)
    at org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder.postProcessRequest(MockHttpServletRequestBuilder.java:831)
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:173)
 

И если в тесте есть только один perform вызов, все работает правильно.

Кто-нибудь может помочь решить эту проблему, пожалуйста.

Ответ №1:

У меня была та же проблема, я решил ее, добавив следующий метод в свой фильтр MockSpringSecurityFilter

 public void getFilters(MockHttpServletRequest mockHttpServletRequest){}
 

Комментарии:

1. Большое спасибо за ваш ответ. Это действительно работает! Могу ли я считать, что где-то есть дефект?