Spring Boot测试RestController返回404问题排查求助
Gradle项目中开发了一个不含SpringBootApplication的模块,其中的RestController会被打包到包含spring-web和主应用的其他模块中。完整部署后手动测试端点一切正常,但编写无Mock的集成测试时,RestAssured返回404错误,尽管日志显示请求映射已成功加载。
测试代码
@PostgresRepositoryTest(JobsRepository.class) @EnableConfigurationProperties(JobRunrProperties.class) @SpringBootTest(webEnvironment = RANDOM_PORT) @ContextConfiguration(classes = {JobServiceTestConfig.class, JobController.class}) @Tag("Jobs") @EnableWebMvc class JobControllerIntegrationTest { @LocalServerPort private int port; @BeforeEach void setUp() { RestAssured.baseURI = "http://localhost"; RestAssured.port = port; RestAssured.basePath = "/rest/jobs/v1"; RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); } @Test void shouldGetJobStatus() { var jobPagedResponse = given().get("/jobs") .then() .log() .all() .statusCode(OK.getStatusCode()) .extract() .body() .as(JobPagedResponse.class); assertThat(jobPagedResponse).isNotNull(); } }
请求映射加载日志
2024-11-30 16:57:33.077 [main] INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer [] 2024-11-30 16:57:33.621 [main] INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default' [] 2024-11-30 16:57:33.638 [main] INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer [] 2024-11-30 16:57:33.713 [main] INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default' [] 2024-11-30 16:57:33.865 [main] TRACE o.s.w.s.m.m.a.RequestMappingHandlerMapping - c.c.j.r.v.JobController: {POST [/rest/jobs/v1/jobs], consumes [application/json], produces [application/json]}: createSelfManagedJob(JobNew) {POST [/rest/jobs/v1/jobs/{jobId}/updateProgress], consumes [application/json], produces [application/json]}: updateSelfManagedJob(UUID,JobUpdate) {GET [/rest/jobs/v1/jobs], produces [application/json]}: findJobs(String,String,List,List,List,UUID,String,String,String,Integer) {DELETE [/rest/jobs/v1/jobs/{jobId}]}: deleteJob(UUID) {GET [/rest/jobs/v1/jobs/{jobId}], produces [application/json]}: getJob(UUID) [] 2024-11-30 16:57:33.868 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - 5 mappings in 'requestMappingHandlerMapping' [] 2024-11-30 16:57:33.871 [main] DEBUG o.s.w.s.h.BeanNameUrlHandlerMapping - Detected 0 mappings in 'beanNameHandlerMapping' [] 2024-11-30 16:57:33.874 [main] TRACE o.s.w.s.f.s.RouterFunctionMapping - 0 RouterFunction(s) in 'routerFunctionMapping' [] 2024-11-30 16:57:33.889 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerAdapter - ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice [] 2024-11-30 16:57:33.910 [main] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - ControllerAdvice beans: 1 @ExceptionHandler, 1 ResponseBodyAdvice [] 2024-11-30 16:57:34.552 [main] INFO o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"] [] 2024-11-30 16:57:34.560 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8080 (http) with context path '/' [] 2024-11-30 16:57:34.562 [main] TRACE o.s.w.s.resource.ResourceUrlProvider - No resource handling mappings found [] 2024-11-30 16:57:34.562 [main] INFO c.c.j.r.v.JobControllerIntegrationTest - Started JobControllerIntegrationTest in 5.009 seconds (process running for 5.66) []
RestAssured返回的404响应
HTTP/1.1 404 Content-Type: text/html;charset=utf-8 Content-Language: en Content-Length: 683 Date: Sat, 30 Nov 2024 16:57:35 GMT Keep-Alive: timeout=60 Connection: keep-alive <html lang="en"> <head> <title>HTTP Status 404 – Not Found</title> <style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style> </head> <body> <h1>HTTP Status 404 – Not Found</h1> <hr class="line"/> <p> <b>Type</b> Status Report </p> <p> <b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists. </p> <hr class="line"/> <h3>Apache Tomcat/10.1.33</h3> </body> </html> Request method: GET Request URI: http://localhost:8080/rest/jobs/v1/jobs Proxy: <none> Request params: <none> Query params: <none> Form params: <none> Path params: <none> Headers: Accept=*/* Cookies: <none> Multiparts: <none> Body: <none>
排查解决方法
移除冲突的
@PostgresRepositoryTest注解@PostgresRepositoryTest是针对仓库层的专用测试注解,它会限制Spring上下文仅加载与仓库相关的组件,和@SpringBootTest混用会导致Web层的请求映射无法正确注册到Servlet容器。直接删除该注解,若需测试仓库逻辑,单独编写仓库测试类即可。删除冗余的
@EnableWebMvc注解
使用@SpringBootTest时,Spring Boot已自动配置Web MVC核心组件,手动添加@EnableWebMvc会覆盖默认配置,破坏请求映射的处理流程。调整注解优先级
确保@SpringBootTest作为核心注解,优先加载完整的Web上下文。同时检查JobServiceTestConfig是否包含了Controller依赖的所有Bean(如Service、Repository等),避免因依赖缺失导致请求无法处理。验证请求路径与上下文
日志显示映射路径是/rest/jobs/v1/jobs,但可以在测试中打印完整请求URL,或通过Spring上下文获取RequestMappingHandlerMappingBean,手动输出所有注册的映射,确认路径完全匹配(比如是否存在未配置的上下文路径)。修改后的测试代码示例
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @EnableConfigurationProperties(JobRunrProperties.class) @ContextConfiguration(classes = {JobServiceTestConfig.class, JobController.class}) @Tag("Jobs") class JobControllerIntegrationTest { @LocalServerPort private int port; @BeforeEach void setUp() { RestAssured.baseURI = "http://localhost"; RestAssured.port = port; RestAssured.basePath = "/rest/jobs/v1"; RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); } @Test void shouldGetJobStatus() { var jobPagedResponse = given() .accept(MediaType.APPLICATION_JSON_VALUE) .get("/jobs") .then() .log().all() .statusCode(HttpStatus.OK.value()) .extract() .body() .as(JobPagedResponse.class); assertThat(jobPagedResponse).isNotNull(); } }
额外排查点:
- 确认
JobController上的@RestController注解拼写正确 - 查看测试启动日志是否有Web MVC初始化的警告或错误,比如缺少必要的Bean导致请求处理链断裂
内容的提问来源于stack exchange,提问作者rojanu

