Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking RestTemplateBuilder and RestTemplate in Spring integration test

I have a REST resource that gets a RestTemplateBuilder injected to build a RestTemplate:

public MyClass(final RestTemplateBuilder restTemplateBuilder) {
    this.restTemplate = restTemplateBuilder.build();
}

I would like to test that class. I need to mock the calls the RestTemplate makes to another service:

request = restTemplate.getForEntity(uri, String.class);

I tried this in my IT:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyIT {

@Autowired
private TestRestTemplate testRestTemplate;
@MockBean
private RestTemplateBuilder restTemplateBuilder;
@Mock
private RestTemplate restTemplate;

@Test
public void shouldntFail() throws IOException {

    ResponseEntity<String> responseEntity = new ResponseEntity<>(HttpStatus.NOT_FOUND);
    when(restTemplateBuilder.build()).thenReturn(restTemplate);
    when(restTemplate.getForEntity(any(URI.class), any(Class.class))).thenReturn(responseEntity);
...
ResponseEntity<String> response = testRestTemplate.postForEntity("/endpoint", request, String.class);
  ...
}
}

When I run the test, I get the following exception:

java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.test.web.client.TestRestTemplate': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: RestTemplate must not be null

How do I do this correctly?

like image 342
user3629892 Avatar asked Mar 06 '18 10:03

user3629892


People also ask

Can we mock RestTemplate?

We can use Mockito to mock the RestTemplate altogether. With this approach, testing our service would be as simple as any other test involving mocking. In the above JUnit test class, we first asked Mockito to create a dummy RestTemplate instance using the @Mock annotation.

What is the difference between TestRestTemplate and RestTemplate?

TestRestTemplate is not an extension of RestTemplate, but rather an alternative that simplifies integration testing and facilitates authentication during tests. It helps in customization of Apache HTTP client, but also it can be used as a wrapper of RestTemplate.

What is RestClientTest?

What is @RestClientTest? @RestClientTest is another one of Spring Boot's annotations used to test a specific slice of your application. As the name suggests, you can use it to test the REST clients inside your application. Applied to a test class it will disable the full-auto-configuration.


1 Answers

Your problem is the order of execution. The context is created containing your MockBean before you have a chance to set it up in your @Test. The solution is to provide a RestTemplateBuilder that's already fully setup when it's inserted into the context. You can do that like this.

Add the following to your @SpringBootTest annotation. Where TestApplication is your Spring Boot application class.

classes = {TestApplication.class, MyIT.ContextConfiguration.class},

Modify your class members thus, deleting your restTemplate and restTemplateBuilder.

@Autowired
private TestRestTemplate testRestTemplate;

Add a static inner class to your MyIT class:

@Configuration
static class ContextConfiguration {
  @Bean
  public RestTemplateBuilder restTemplateBuilder() {

    RestTemplateBuilder rtb = mock(RestTemplateBuilder.class);
    RestTemplate restTemplate = mock(RestTemplate.class);

    when(rtb.build()).thenReturn(restTemplate);
    return rtb;
  }
}

In your tests, modify the RestTemplate mock to do whatever you want:

@Test
public void someTest() {

  when(testRestTemplate.getRestTemplate().getForEntity(...
}
like image 73
Andy Brown Avatar answered Oct 12 '22 13:10

Andy Brown