为什么在启用了Spring Security的情况下,MockMvc在有效路径上返回404错误?

huangapple go评论92阅读模式
英文:

Why does MockMvc in return 404 error on valid path with Spring Security enabled?

问题

Sure, here is the translated content:

  1. @SpringBootTest
  2. @WebAppConfiguration
  3. class UserControllerImplTest {
  4. private MockMvc mockMvc;
  5. @Autowired
  6. private WebApplicationContext wac;
  7. @Autowired
  8. private AuthCookieFilter authCookieFilter;
  9. @MockBean
  10. private UserDTOService userDTOService;
  11. @MockBean
  12. private ImageDTOService imageDTOService;
  13. @BeforeEach
  14. public void setUp() {
  15. mockMvc = MockMvcBuilders.webAppContextSetup(wac)
  16. .addFilter(authCookieFilter).build();
  17. }
  18. @Test
  19. public void whenUsers_shouldReturnUsers() throws Exception {
  20. UserDTO user1 = getSampleUser("user1");
  21. UserDTO user2 = getSampleUser("user2");
  22. UserDTO user3 = getSampleUser("user3");
  23. List<UserDTO> users = List.of(user1, user2, user3);
  24. Mockito.when(userDTOService.getAll()).thenReturn(users);
  25. mockMvc.perform(get("/user"))
  26. .andExpect(status().isOk())
  27. .andExpect(content().string(users.toString()));
  28. }
  29. private UserDTO getSampleUser(String username) {
  30. return UserDTO.builder()
  31. .username(username)
  32. .email(username + "@example.com")
  33. .password("password")
  34. .registerTime(LocalDateTime.now())
  35. .isActive(true)
  36. .build();
  37. }
  38. }

Please note that the code has been translated as per your request, but I'm not sure whether the code itself is free of issues or will execute successfully. If you encounter any errors or issues, feel free to ask for assistance.

英文:

I'm trying to test my Spring Boot REST Controller with MockMvc. Following is my test class:

UserControllerImplTest (version 1)

  1. @SpringBootTest
  2. @AutoConfigureMockMvc
  3. class UserControllerImplTest {
  4. @Autowired
  5. private MockMvc mockMvc;
  6. @MockBean
  7. private UserDTOService userDTOService;
  8. @MockBean
  9. private ImageDTOService imageDTOService;
  10. @Test
  11. public void whenUsers_shouldReturnUsers() throws Exception {
  12. UserDTO user1 = getSampleUser(&quot;user1&quot;);
  13. UserDTO user2 = getSampleUser(&quot;user2&quot;);
  14. UserDTO user3 = getSampleUser(&quot;user3&quot;);
  15. List&lt;UserDTO&gt; users = List.of(user1, user2, user3);
  16. Mockito.when(userDTOService.getAll()).thenReturn(users);
  17. mockMvc.perform(get(&quot;/user&quot;))
  18. .andExpect(status().isOk())
  19. .andExpect(content().string(users.toString()));
  20. }
  21. private UserDTO getSampleUser(String username) {
  22. return UserDTO.builder()
  23. .username(username)
  24. .email(username + &quot;@example.com&quot;)
  25. .password(&quot;password&quot;)
  26. .registerTime(LocalDateTime.now())
  27. .isActive(true)
  28. .build();
  29. }
  30. }

Controller to be tested:
UserController:

  1. @Api(tags={&quot;User info&quot;})
  2. @RequestMapping(&quot;/user&quot;)
  3. public interface UserController {
  4. @ApiOperation(value = &quot;Returns list of users&quot;)
  5. @GetMapping(&quot;/&quot;)
  6. @PreAuthorize(&quot;hasRole(&#39;ROLE_ADMIN&#39;)&quot;)
  7. ResponseEntity&lt;List&lt;UserDTO&gt;&gt; users();
  8. @ApiOperation(value = &quot;Returns single user&quot;)
  9. @GetMapping(&quot;/{username}&quot;)
  10. ResponseEntity&lt;UserDTO&gt; userInfo(@PathVariable String username);
  11. @ApiOperation(value = &quot;Returns list of images uploaded by user authenticated with session cookie&quot;)
  12. @GetMapping(&quot;/images&quot;)
  13. @PreAuthorize(&quot;isFullyAuthenticated()&quot;)
  14. ResponseEntity&lt;List&lt;ImageDTO&gt;&gt; userImages(@AuthenticationPrincipal CustomUserDetails userDetails
  15. );
  16. }

its implementation:
UserControllerImpl

  1. @Service
  2. @RequiredArgsConstructor
  3. public class UserControllerImpl implements UserController {
  4. private final UserDTOService userDTOService;
  5. private final ImageDTOService imageDTOService;
  6. @Override
  7. public ResponseEntity&lt;List&lt;UserDTO&gt;&gt; users() {
  8. return ResponseEntity.status(HttpStatus.OK).body(List.of(UserDTO.builder().username(&quot;aaa&quot;).build()));
  9. // Optional&lt;List&lt;UserDTO&gt;&gt; users = Optional.ofNullable(userDTOService.getAll());
  10. // if (users.isEmpty()) {
  11. // return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
  12. // }
  13. //
  14. // return ResponseEntity.status(HttpStatus.OK).body(users.get());
  15. }
  16. @Override
  17. public ResponseEntity&lt;UserDTO&gt; userInfo(String username) {
  18. Optional&lt;UserDTO&gt; requestedUser = Optional.ofNullable(userDTOService.findByUsername(username));
  19. if (requestedUser.isEmpty()) {
  20. return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
  21. }
  22. return ResponseEntity.status(HttpStatus.OK).body(requestedUser.get());
  23. }
  24. @Override
  25. public ResponseEntity&lt;List&lt;ImageDTO&gt;&gt; userImages(@AuthenticationPrincipal CustomUserDetails userDetails) {
  26. UserDTO user = userDetails.getUser();
  27. Optional&lt;List&lt;ImageDTO&gt;&gt; images = Optional.ofNullable(imageDTOService.findAllUploadedBy(user));
  28. if (images.isEmpty()) {
  29. return ResponseEntity.status(HttpStatus.OK).body(Collections.emptyList());
  30. }
  31. return ResponseEntity.status(HttpStatus.OK).body(images.get());
  32. }
  33. }

The method I'm invoked in the controller (users()) was modified, just to be sure it'll always return 200.

The test fails because of:

  1. java.lang.AssertionError: Status expected:&lt;200&gt; but was:&lt;404&gt;
  2. Expected :200
  3. Actual :404

I had a strong suspicion that the Filter Bean I defined might be a culprit here.

AuthCookieFilter

  1. @RequiredArgsConstructor
  2. @Component
  3. public class AuthCookieFilter extends GenericFilterBean {
  4. private final SessionDTOService sessionDTOService;
  5. private final AppConfig appConfig;
  6. @Override
  7. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  8. Optional&lt;String&gt; sessionId = Optional.ofNullable(extractAuthCookie((HttpServletRequest) servletRequest));
  9. if (sessionId.isPresent()) {
  10. Optional&lt;SessionDTO&gt; sessionDTO = Optional.ofNullable(sessionDTOService.findByIdentifier(sessionId.get()));
  11. if (sessionDTO.isPresent()) {
  12. UserDTO userDTO = sessionDTO.get().getUser();
  13. CustomUserDetails customUserDetails = new CustomUserDetails(userDTO);
  14. SecurityContextHolder.getContext().setAuthentication(new UserAuthentication(customUserDetails));
  15. }
  16. }
  17. HttpServletResponse response = (HttpServletResponse) servletResponse;
  18. response.setHeader(&quot;Access-Control-Allow-Origin&quot;, appConfig.getCorsHosts());
  19. response.setHeader(&quot;Access-Control-Allow-Methods&quot;, &quot;POST, PUT, GET, OPTIONS, DELETE&quot;);
  20. response.setHeader(&quot;Access-Control-Max-Age&quot;, &quot;3600&quot;);
  21. response.setHeader(&quot;Access-Control-Allow-Headers&quot;, &quot;Access-Control-Allow-Origin, Authorization, Content-Type, Cache-Control&quot;);
  22. response.setHeader(&quot;Access-Control-Allow-Credentials&quot;, &quot;true&quot;);
  23. filterChain.doFilter(servletRequest, response);
  24. }
  25. public static String extractAuthCookie(HttpServletRequest request) {
  26. List&lt;Cookie&gt; cookies = Arrays.asList(Optional.ofNullable(request.getCookies()).orElse(new Cookie[0]));
  27. if (!cookies.isEmpty()) {
  28. Optional&lt;Cookie&gt; authCookie = cookies.stream()
  29. .filter(cookie -&gt; cookie.getName().equals(&quot;authentication&quot;))
  30. .findFirst();
  31. if (authCookie.isPresent()) {
  32. return authCookie.get().getValue();
  33. }
  34. }
  35. return null;
  36. }
  37. }

So I decided to configure MockMvc manually, explicitly adding it to the context:
UserControllerImplTest (version 2)

  1. @SpringBootTest
  2. @WebAppConfiguration
  3. class UserControllerImplTest {
  4. private MockMvc mockMvc;
  5. @Autowired
  6. private WebApplicationContext wac;
  7. @Autowired
  8. private AuthCookieFilter authCookieFilter;
  9. @MockBean
  10. private UserDTOService userDTOService;
  11. @MockBean
  12. private ImageDTOService imageDTOService;
  13. @BeforeEach
  14. public void setUp() {
  15. mockMvc = MockMvcBuilders.webAppContextSetup(wac)
  16. .addFilter(authCookieFilter).build();
  17. }
  18. @Test
  19. public void whenUsers_shouldReturnUsers() throws Exception {
  20. UserDTO user1 = getSampleUser(&quot;user1&quot;);
  21. UserDTO user2 = getSampleUser(&quot;user2&quot;);
  22. UserDTO user3 = getSampleUser(&quot;user3&quot;);
  23. List&lt;UserDTO&gt; users = List.of(user1, user2, user3);
  24. Mockito.when(userDTOService.getAll()).thenReturn(users);
  25. mockMvc.perform(get(&quot;/user&quot;))
  26. .andExpect(status().isOk())
  27. .andExpect(content().string(users.toString()));
  28. }
  29. private UserDTO getSampleUser(String username) {
  30. return UserDTO.builder()
  31. .username(username)
  32. .email(username + &quot;@example.com&quot;)
  33. .password(&quot;password&quot;)
  34. .registerTime(LocalDateTime.now())
  35. .isActive(true)
  36. .build();
  37. }
  38. }

But had no success, still getting 404s.

I also considered limiting the test scope to bringing up only the Web layer, by using @WebMvcTest, but my AuthCookieFilter, as you can see above, requires full Spring context to be up.

I noticed, that debugger stops inside doFilter of AuthCookieFilter when I put a breakpoint there, disregarding whether MockMvc is configured automatically or manually. However I cannot reach a breakpoint set inside UserControllerImpl.users().

Web security is enabled in this app and that's were additional filter is being added:
SecurityConfiguration.class

  1. @EnableGlobalMethodSecurity(prePostEnabled = true)
  2. @EnableWebSecurity
  3. @Configuration
  4. @RequiredArgsConstructor
  5. public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  6. private final CustomUserDetailsService userDetailsService;
  7. private final CustomLogoutSuccessHandler customLogoutSuccessHandler;
  8. private final AuthCookieFilter authCookieFilter;
  9. @Override
  10. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  11. auth.userDetailsService(userDetailsService)
  12. .passwordEncoder(getPasswordEncoder());
  13. }
  14. @Bean
  15. @Override
  16. protected AuthenticationManager authenticationManager() {
  17. return authentication -&gt; {
  18. throw new AuthenticationServiceException(&quot;Cannot authenticate &quot; + authentication);
  19. };
  20. }
  21. @Override
  22. protected void configure(HttpSecurity http) throws Exception {
  23. http
  24. .sessionManagement(configurer -&gt; configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
  25. .csrf().disable()
  26. .logout(configurer -&gt; {
  27. configurer.addLogoutHandler(new HeaderWriterLogoutHandler(
  28. new ClearSiteDataHeaderWriter(ClearSiteDataHeaderWriter.Directive.ALL)
  29. ));
  30. configurer.logoutSuccessHandler(customLogoutSuccessHandler);
  31. configurer.logoutUrl(&quot;/auth/logout&quot;);
  32. configurer.deleteCookies(&quot;authentication&quot;);
  33. })
  34. .exceptionHandling(configurer -&gt; configurer.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)))
  35. .addFilterAfter(authCookieFilter, SecurityContextPersistenceFilter.class)
  36. .authorizeRequests()
  37. .antMatchers(&quot;/auth/*&quot;).permitAll()
  38. .and()
  39. .formLogin().permitAll()
  40. ;
  41. }
  42. @Bean
  43. public PasswordEncoder getPasswordEncoder() {
  44. String defaultEncodingId = &quot;argon2&quot;;
  45. Map&lt;String, PasswordEncoder&gt; encoders = new HashMap&lt;&gt;();
  46. encoders.put(defaultEncodingId, new Argon2PasswordEncoder(16, 32, 8, 1 &lt;&lt; 16, 4));
  47. return new DelegatingPasswordEncoder(defaultEncodingId, encoders);
  48. }
  49. }

Here are logs of the application start-up and test execution:

  1. 21:40:56.203 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating CacheAwareContextLoaderDelegate from class [org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate]
  2. 21:40:56.210 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating BootstrapContext using constructor [public org.springframework.test.context.support.DefaultBootstrapContext(java.lang.Class,org.springframework.test.context.CacheAwareContextLoaderDelegate)]
  3. 21:40:56.228 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating TestContextBootstrapper for test class [com.ewsie.allpic.user.controller.impl.UserControllerImplTest] from class [org.springframework.boot.test.context.SpringBootTestContextBootstrapper]
  4. 21:40:56.237 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Neither @ContextConfiguration nor @ContextHierarchy found for test class [com.ewsie.allpic.user.controller.impl.UserControllerImplTest], using SpringBootContextLoader
  5. 21:40:56.240 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.ewsie.allpic.user.controller.impl.UserControllerImplTest]: class path resource [com/ewsie/allpic/user/controller/impl/UserControllerImplTest-context.xml] does not exist
  6. 21:40:56.240 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.ewsie.allpic.user.controller.impl.UserControllerImplTest]: class path resource [com/ewsie/allpic/user/controller/impl/UserControllerImplTestContext.groovy] does not exist
  7. 21:40:56.240 [main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [com.ewsie.allpic.user.controller.impl.UserControllerImplTest]: no resource found for suffixes {-context.xml, Context.groovy}.
  8. 21:40:56.241 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [com.ewsie.allpic.user.controller.impl.UserControllerImplTest]: UserControllerImplTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
  9. 21:40:56.276 [main] DEBUG org.springframework.test.context.support.ActiveProfilesUtils - Could not find an &#39;annotation declaring class&#39; for annotation type [org.springframework.test.context.ActiveProfiles] and class [com.ewsie.allpic.user.controller.impl.UserControllerImplTest]
  10. 21:40:56.320 [main] DEBUG org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider - Identified candidate component class: file [/home/max/Projects/allpic/allpic-backend/target/classes/com/ewsie/allpic/AllpicApplication.class]
  11. 21:40:56.321 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration com.ewsie.allpic.AllpicApplication for test class com.ewsie.allpic.user.controller.impl.UserControllerImplTest
  12. 21:40:56.382 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - @TestExecutionListeners is not present for class [com.ewsie.allpic.user.controller.impl.UserControllerImplTest]: using defaults.
  13. 21:40:56.382 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener, org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener, org.springframework.security.test.context.support.ReactorContextTestExecutionListener]
  14. 21:40:56.391 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@7e22550a, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@45e37a7e, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@62452cc9, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@6941827a, org.springframework.test.context.support.DirtiesContextTestExecutionListener@5a7005d, org.springframework.test.context.transaction.TransactionalTestExecutionListener@5bc9ba1d, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@1021f6c9, org.springframework.test.context.event.EventPublishingTestExecutionListener@7516e4e5, org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener@488eb7f2, org.springframework.security.test.context.support.ReactorContextTestExecutionListener@5e81e5ac, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@4189d70b, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@3fa2213, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@3e7634b9, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@6f0b0a5e, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@6035b93b]
  15. 21:40:56.393 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test class: context [DefaultTestContext@2a8d39c4 testClass = UserControllerImplTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@25b2cfcb testClass = UserControllerImplTest, locations = &#39;{}&#39;, classes = &#39;{class com.ewsie.allpic.AllpicApplication}&#39;, contextInitializerClasses = &#39;[]&#39;, activeProfiles = &#39;{}&#39;, propertySourceLocations = &#39;{}&#39;, propertySourceProperties = &#39;{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}&#39;, contextCustomizers = set[[ImportsContextCustomizer@72758afa key = [org.springframework.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebClientAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebDriverAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@30b6ffe0, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@14f232c4, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@d324b662, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@f627d13, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@4b3fa0b3, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@479cbee5], resourceBasePath = &#39;src/main/webapp&#39;, contextLoader = &#39;org.springframework.boot.test.context.SpringBootContextLoader&#39;, parent = [null]], attributes = map[&#39;org.springframework.test.context.web.ServletTestExecutionListener.activateListener&#39; -&gt; true]], class annotated with @DirtiesContext [false] with mode [null].
  16. 21:40:56.409 [main] DEBUG org.springframework.test.context.support.TestPropertySourceUtils - Adding inlined properties to environment: {spring.jmx.enabled=false, org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=-1}
  17. 2020-09-13 21:40:56.599 INFO 52850 --- [ main] c.e.a.u.c.impl.UserControllerImplTest : Starting UserControllerImplTest on Oyashiro-sama with PID 52850 (started by max in /home/max/Projects/allpic/allpic-backend)
  18. 2020-09-13 21:40:56.599 INFO 52850 --- [ main] c.e.a.u.c.impl.UserControllerImplTest : No active profile set, falling back to default profiles: default
  19. 2020-09-13 21:40:57.143 INFO 52850 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
  20. 2020-09-13 21:40:57.197 INFO 52850 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 49ms. Found 5 JPA repository interfaces.
  21. 2020-09-13 21:40:57.716 INFO 52850 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean &#39;org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration&#39; of type [org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
  22. 2020-09-13 21:40:57.722 INFO 52850 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean &#39;objectPostProcessor&#39; of type [org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
  23. 2020-09-13 21:40:57.723 INFO 52850 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean &#39;org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler@1de08775&#39; of type [org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
  24. 2020-09-13 21:40:57.727 INFO 52850 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean &#39;org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration&#39; of type [org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
  25. 2020-09-13 21:40:57.731 INFO 52850 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean &#39;methodSecurityMetadataSource&#39; of type [org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
  26. 2020-09-13 21:40:57.872 INFO 52850 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
  27. 2020-09-13 21:40:57.909 INFO 52850 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 5.4.12.Final
  28. 2020-09-13 21:40:57.931 INFO 52850 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
  29. 2020-09-13 21:40:57.993 INFO 52850 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
  30. 2020-09-13 21:40:58.098 INFO 52850 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
  31. 2020-09-13 21:40:58.108 INFO 52850 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
  32. (sql queries here)
  33. 2020-09-13 21:40:58.523 INFO 52850 --- [ main] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
  34. 2020-09-13 21:40:58.527 INFO 52850 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit &#39;default&#39;
  35. 2020-09-13 21:40:59.025 WARN 52850 --- [ main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
  36. 2020-09-13 21:40:59.661 INFO 52850 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@647bd553, org.springframework.security.web.context.SecurityContextPersistenceFilter@16d7f503, com.ewsie.allpic.user.security.AuthCookieFilter@a47a011, org.springframework.security.web.header.HeaderWriterFilter@1b9785aa, org.springframework.security.web.authentication.logout.LogoutFilter@2ddb260e, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@4ceac22d, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@1203c259, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@15311af2, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@54602d5a, org.springframework.security.web.session.SessionManagementFilter@347074a9, org.springframework.security.web.access.ExceptionTranslationFilter@2eebb07, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@441a2d52]
  37. 2020-09-13 21:40:59.901 INFO 52850 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService &#39;applicationTaskExecutor&#39;
  38. 2020-09-13 21:41:00.036 INFO 52850 --- [ main] o.s.b.a.h2.H2ConsoleAutoConfiguration : H2 console available at &#39;/h2-console&#39;. Database available at &#39;jdbc:h2:mem:default&#39;
  39. 2020-09-13 21:41:00.070 INFO 52850 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService &#39;taskScheduler&#39;
  40. 2020-09-13 21:41:00.111 INFO 52850 --- [ main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet &#39;&#39;
  41. 2020-09-13 21:41:00.111 INFO 52850 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet &#39;&#39;
  42. 2020-09-13 21:41:00.118 INFO 52850 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 7 ms
  43. 2020-09-13 21:41:00.428 INFO 52850 --- [ main] c.e.a.u.c.impl.UserControllerImplTest : Started UserControllerImplTest in 4.013 seconds (JVM running for 4.7)
  44. WARNING: An illegal reflective access operation has occurred
  45. WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils (file:/home/max/.m2/repository/org/springframework/spring-core/5.2.5.RELEASE/spring-core-5.2.5.RELEASE.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
  46. WARNING: Please consider reporting this to the maintainers of org.springframework.cglib.core.ReflectUtils
  47. WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
  48. WARNING: All illegal access operations will be denied in a future release
  49. MockHttpServletRequest:
  50. HTTP Method = GET
  51. Request URI = /user
  52. Parameters = {}
  53. Headers = []
  54. Body = null
  55. Session Attrs = {}
  56. Handler:
  57. Type = org.springframework.web.servlet.resource.ResourceHttpRequestHandler
  58. Async:
  59. Async started = false
  60. Async result = null
  61. Resolved Exception:
  62. Type = null
  63. ModelAndView:
  64. View name = null
  65. View = null
  66. Model = null
  67. FlashMap:
  68. Attributes = null
  69. MockHttpServletResponse:
  70. Status = 404
  71. Error message = null
  72. Headers = [Access-Control-Allow-Origin:&quot;http://localhost:4200&quot;, Access-Control-Allow-Methods:&quot;POST, PUT, GET, OPTIONS, DELETE&quot;, Access-Control-Max-Age:&quot;3600&quot;, Access-Control-Allow-Headers:&quot;Access-Control-Allow-Origin, Authorization, Content-Type, Cache-Control&quot;, Access-Control-Allow-Credentials:&quot;true&quot;, Vary:&quot;Origin&quot;, &quot;Access-Control-Request-Method&quot;, &quot;Access-Control-Request-Headers&quot;, X-Content-Type-Options:&quot;nosniff&quot;, X-XSS-Protection:&quot;1; mode=block&quot;, Cache-Control:&quot;no-cache, no-store, max-age=0, must-revalidate&quot;, Pragma:&quot;no-cache&quot;, Expires:&quot;0&quot;, X-Frame-Options:&quot;DENY&quot;]
  73. Content type = null
  74. Body =
  75. Forwarded URL = null
  76. Redirected URL = null
  77. Cookies = []
  78. java.lang.AssertionError: Status expected:&lt;200&gt; but was:&lt;404&gt;
  79. Expected :200
  80. Actual :404

How can I make the MockMvc work and mock my controller?

答案1

得分: 3

问题在于 /user 确实无处可寻,因此 404 响应是完全合理的。

在更改后:

mockMvc.perform(get(&quot;/user&quot;))

为:

mockMvc.perform(get(&quot;/user/&quot;))
(注意末尾的 /

我能够收到实际的响应并继续进行测试。

英文:

The problem was that /user was indeed nowhere to be found, so 404 response was completely justified.

After chaniging:

mockMvc.perform(get(&quot;/user&quot;))

to:

mockMvc.perform(get(&quot;/user/&quot;))
(note the trailing /)

I was able to recieve the actual response and carry on with the test.

答案2

得分: 2

在我的情况下,我使用 @Import 手动导入了控制器类,并且它起作用了。似乎控制器 Bean 没有被 @WebMvcTest 导入。请看下面的代码:

  1. @ContextConfiguration(
  2. classes = [TestConfigs::class]
  3. )
  4. @WebMvcTest
  5. @Import(MyController::class)
  6. class MyControllerTests {
  7. @Test
  8. fun testPost() {
  9. // 测试逻辑放在这里
  10. }
  11. }

请注意我如何使用 @Import@Import(MyController::class)

如果我移除 @Import,我会得到 404 错误。

希望有所帮助。

英文:

In my case, I imported the controller class manually using @Import and it worked. It seems the controller bean had not been imported by @WebMvcTest. See below code :

  1. @ContextConfiguration(
  2. classes = [TestConfigs::class]
  3. )
  4. @WebMvcTest
  5. @Import(MyController::class)
  6. class MyControllerTests {
  7. @Test
  8. fun testPost() {
  9. //test logic goes here
  10. }
  11. }

Note that how I used @Import : @Import(MyController::class).

If I remove @Import, I would get 404.

Hope it helps

答案3

得分: 1

尝试将控制器中的接口移除。

在我的情况下,只有这个操作会导致404错误。如果我在控制器中添加任何接口定义,测试中就会出现404错误,但在工作模式下我的控制器正常工作。我仍在调查这个问题,我认为测试框架不能正确地使用接口定义注册控制器。

已解决

  1. @Import(AopAutoConfiguration.class)

https://stackoverflow.com/a/56504756/20816770

英文:

Try to remove interface from controller.

In my case only this cause 404 error, if I add any interface definition to my controller, I get 404 error in tests, but in work mode my controller working fine. I still investigating this issue, I think test framework cannot register controller correcly with interface definition.

Resolved:

  1. @Import(AopAutoConfiguration.class)

https://stackoverflow.com/a/56504756/20816770

huangapple
  • 本文由 发表于 2020年9月14日 03:50:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/63874954.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定