Search code examples
spring-bootintegration-testingresttemplatemockmvc

SpringBoot integration test - TestRestTemplate doesn't reach controller and get 404 instead of 200


I was trying to play a little bit with integration test in springboot, hence I build some sample test using @SpringBootTest annotation. My sample test is :

     @RunWith(SpringRunner.class)
     @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
     @ContextConfiguration(classes = IntegrationTestConfig.class)
        public class WeatherForCityIT {


            @Autowired
            private TestRestTemplate restTemplate;



            @Test
            public void getWeatherForExistingCity() throws Exception {

                String existingCity = "London";

                ResponseEntity<String> responseEntity = restTemplate.getForEntity("/weather/{cityName}",String.class,existingCity.toString());
                Assertions.assertThat(responseEntity).isNotNull();


            }
        }

And have following controller class

@RestController
@RequestMapping("/weather")
public class ChartController {

    private WeatherForecastAPI weatherForecastAPI;

    @Autowired
    public void setWeatherForecastAPI(WeatherForecastAPI weatherForecastAPI) {
        this.weatherForecastAPI = weatherForecastAPI;
    }

    @GetMapping("/{cityName}")
    public List<WeatherForecastDTO> get5daysForecast(@PathVariable String cityName) {

        weatherForecastAPI.getWeatherForecastByCity(cityWithCountryCode.toString());            
    }

}

Unfortunately in response body I get message 404 Not Found. In debug mode I see that it never reaches defined controller. Am I missing something from configuration perspective ? I was trying to also use MockMvc :

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@ContextConfiguration(classes = IntegrationTestConfig.class)
public class WeatherForCityIT {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void getWeatherForExistingCity() throws Exception {

        String existingCity = "London";

        restTemplate.getForEntity("/weather/{cityName}",String.class,existingCity);

        mockMvc.perform(get("/weather/" + existingCity))
               .andDo(print())
               .andExpect(MockMvcResultMatchers.status().isOk());
    }
}

but also without success (again 404 instead of 202).

EDITED

Configuration class looks following:

@Configuration
@EnableAutoConfiguration
public class IntegrationTestConfig {

    @Bean
    public com.jayway.jsonpath.Configuration configuration() {

        return com.jayway.jsonpath.Configuration.builder()
                                                .jsonProvider(new JacksonJsonProvider())
                                                .mappingProvider(new JacksonMappingProvider())
                                                .options(EnumSet.noneOf(Option.class))
                                                .build();
    }

}

Solution

  • You do not need @EnableAutoConfiguration in your test configuration class. Therefore IntegrationTestConfig should look like:

    @TestConfiguration
    public class IntegrationTestConfig {
    
        @Bean
        public com.jayway.jsonpath.Configuration configuration() {
    
            return com.jayway.jsonpath.Configuration.builder()
                    .jsonProvider(new JacksonJsonProvider())
                    .mappingProvider(new JacksonMappingProvider())
                    .options(EnumSet.noneOf(Option.class))
                    .build();
        }
    }
    

    Your WeatherForCityIT should remain as in you sample code:

    @RunWith(SpringRunner.class)
         @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
         @ContextConfiguration(classes = IntegrationTestConfig.class)
    public class WeatherForCityIT {
         // your code here...
    }
    

    Regarding the exception message you are receiving:

    No qualifying bean of type 'com.jayway.jsonpath.Configuration' available: expected single matching bean but found 2: getConfiguration,configuration)

    From the error message you know that you have 2 beans of the same type (com.jayway.jsonpath.Configuration) in your context:

    1. Bean with name getConfiguration
    2. Bean with name configuration

    The bean configuration is defined in your IntegrationTestConfig, the other bean getConfiguration is defined in one of your configuration classes. Somewhere in your application you are autowiring 'com.jayway.jsonpath.Configuration' bean by type. Since you have 2 beans of this type, Spring is complaining with the exception.

    Do you need both of these beans? If not, delete one of the beans. Otherwise consider using @Qualifier annotation when autowiring beans.