23

I've got a problem while testing a Spring Controller. I'm using the annotation @WebMvcTest in my test class. When I run the test, I get this error: No qualifying bean of type 'org.springframework.boot.web.client.RestTemplateBuilder' available

I'm using RestTemplate for other classes in my project so I've defined a bean in my main class:

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.build();
}

To make it work, I have to define my restTemplate bean this way:

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

Is it a problem with the annotation @WebMvcTest or did I miss something?

Thanks

Alexandre
  • 259
  • 1
  • 3
  • 6
  • 1
    just jumped into the same issue, it looks like a bug to me and can't find much goggling around. Do you have any update? – Paizo Feb 01 '17 at 13:19

3 Answers3

39

Yes, this does feel like a bug.
However you can solve it easily by adding @AutoConfigureWebClient to your test class along with the existing @WebMvcTest

Patrick Herrera
  • 3,120
  • 26
  • 21
  • 3
    This solution fixes the problem for me. It feels like we are stepping into undocumented territory when we try to use test slices. Spring creates some beans for us during testing, but some - like RestTemplateBuilder - are mysteriously absent unless we sprinkle this magic fairy dust as you suggest. – Gary Jul 25 '17 at 16:22
  • 2
    I agree @Gary, I lodged an issue for this (https://github.com/spring-projects/spring-boot/issues/8784) but it was closed as duplicate of https://github.com/spring-projects/spring-boot/issues/7999. – Patrick Herrera Jul 26 '17 at 23:25
  • 2
    However I've changed my mind about this being a bug and I think it is just an example of how test slices can trip you up with regards to autowiring and the fact that you shouldn't make any assumptions about any beans being available when using the slicing functions. It feels like a bug because the RestTemplate seems to go hand-in-hand with testing MVC, but ask yourself whether you are actually using that RestTemplate in the test? You might need to restructure your application with respect to what is scanned during tests. – Patrick Herrera Jul 27 '17 at 00:02
4

when you add any argument to the @Bean definition it means that you are looking for a bean of type T mentioned to be injected . Change this :

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.build();
}

to

 @Bean
    public RestTemplate restTemplate() {

       RestTemplateBuilder builder=new RestTemplateBuilder(//pass customizers);

        return builder.build();
    }
Barath
  • 5,093
  • 1
  • 17
  • 42
  • 6
    Ok this works but accordingly to the Spring documentation, Spring-Boot provides a RestTemplateBuilder bean, that's why I shouldn't have to create another one -> https://spring.io/guides/gs/consuming-rest/. Besides everything works well when I launch my application, it's only in the unit test... – Alexandre Jan 20 '17 at 13:05
4

When I'm writing my Controller tests, I generally prefer to use mocks for all the collaborators. This makes it super easy to verify your beans are getting called with the values that you expect, without actually performing the call.

With WebMvcTest this is super easy to pull off, below is an example given your RestTemplate Bean.

@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
public class SomeControllerTest {

   @MockBean
   private RestTemplate restTemplate;

   @Test
   public void get_WithData() {
      mockMvc.perform(get("/something")).andExpect(status().isOk());
      verify(restTemplate, times(1)).getForObject("http://localhost:8080/something", SomeClass.class);
   }
}
lane.maxwell
  • 5,002
  • 1
  • 20
  • 30
  • 3
    But the controller I'm testing doesn't use the RestTemplate. If I create a MockBean in my test class it works: @MockBean private RestTemplateBuilder restTemplateBuilder; However this mockBean is not used, it's a workaround to avoid this error but it adds useless attributes in my test class... – Alexandre Jan 20 '17 at 13:17