Search code examples
javaspringspring-bootintegration-testing

Spring Boot Test RestController returns 404


I'm building a module in a gradle project which doesn't have the SpringBootApplication and contains RestController which gets bundled into a different module that contains the spring-web and the application. I've manually tested the endpoints in the fully deployed application and all works OK.

I'm aiming to write an integration test suite for the RestController without any mocks. So far I've got

@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();
    }
}

Logs show the request mappings are loaded

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) []

and RestAssured output

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>

Solution

  • I found a solution to the problems I'm having. I've done the following two things to be able to integration test the controller

    1. Removed @PostgresRepositoryTest. This a test slice annotation I created to test the repo layer and it was causing some sort of conflict
    2. Created class with @SpringBootApplication in Integration Test scope

    so that signature of the controller test suite now looks like

    @EnableConfigurationProperties(JobRunrProperties.class)
    @SpringBootTest(
            webEnvironment = RANDOM_PORT,
            classes = {JobController.class, JobServiceTestConfig.class, PostgresRepositoryConfiguration.class})
    @Tag("Jobs")
    class JobControllerIntegrationTest {
    ...
    }