Dave Michaels
Dave Michaels

Reputation: 937

Mockito unit test for rest template

I am trying to write a unit test for rest template that is making http calls. I have created the rest template with the rest template builder, shown below. the rest template is set to configure read and connection timeouts. I also have a retry template that is to execute retries when the application has a timeout. I am at the point where I have specified the http methods: postForEntity, exchange, and getForEntity that need to retried in the retry template and need help with writing unit tests. I started with the getForEntity method but am receiving a different output from what is expected. any assistance with this would be helpful.

Rest Template

 @Bean
public RestTemplate restTemplate() {
    return new RestTemplateBuilder()
            .setConnectTimeout(Duration.ofSeconds(10))
            .setReadTimeout(Duration.ofSeconds(10))
            .build();

}

Retrying getForEntity

 public ResponseEntity getForEntity(URI uri, Class c) {
    return retryTemplate.execute(retryContext -> {
        return restTemplate.getForEntity(uri, c);
    });
}

Unit Test

public class RetryRestTemplateTest {

@Mock
private RestTemplate restTemplate;

@Mock
private RetryTemplate retryTemplate;

private RetryRestTemplate retryRestTemplate;

String testUrl = "http://localhost:8080";

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);

    retryRestTemplate = new RetryRestTemplate(
            restTemplate,
            retryTemplate
    );
}

@Test
public void getForEntity() throws URISyntaxException{
    URI testUri= new URI(testUrl);
    ArgumentCaptor<URI> argument = ArgumentCaptor.forClass(URI.class);

    doReturn(new ResponseEntity<>("ResponseString", HttpStatus.OK))
            .when(restTemplate).getForEntity(any(URI.class), eq(String.class));

    assertThat(restTemplate.getForEntity(testUri, String.class), is(HttpStatus.OK));

    verify(restTemplate).getForEntity(argument.capture(), eq(String.class));
    assertThat(argument.getValue().toString(), is(testUri));
}}

My expected should be is <200 OK> and my actual is <<200 OK OK,ResponseString,[]>>

Any help on this would be helpful as I am not that experienced with Mockito and Junit.

Upvotes: 0

Views: 2280

Answers (1)

Andreas
Andreas

Reputation: 5309

Your expectations are not aligned with the code you wrote getForEntity does not return a HttpStatus instance, instead it returns a ResponseEntity<String>. Comparing a ResponseEntity<String> with a HttpStatus will never yield equal.

A fixed version of your test:

  @Test
  public void getForEntity() throws URISyntaxException {
    URI testUri = new URI(testUrl);
    ArgumentCaptor<URI> argument = ArgumentCaptor.forClass(URI.class);

    doReturn(new ResponseEntity<>("ResponseString", HttpStatus.OK))
        .when(restTemplate).getForEntity(any(URI.class), eq(String.class));

    assertThat(restTemplate.getForEntity(testUri, String.class).getStatusCode(),
        CoreMatchers.is(HttpStatus.OK));

    verify(restTemplate).getForEntity(argument.capture(), eq(String.class));
    assertThat(argument.getValue(), CoreMatchers.is(testUri));
  }

Some side note: The test does not really test getForEntity, it tests that a java proxy you created with mockito does return the mocked result. Imho you are actually testing if the mock framework works...

doReturn(new ResponseEntity<>("ResponseString", HttpStatus.OK)).when(restTemplate).getForEntity(any(URI.class), eq(String.class));

As discussed in the comments, an integration test of the RestTemplate could be:

package com.example.demo;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import java.io.IOException;
import java.net.URI;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

public class RetryRestTemplateTest {

  private final MockWebServer server = new MockWebServer();

  @BeforeEach
  public void setup() throws IOException {
    server.start();
  }

  @AfterEach
  public void teardown() throws IOException {
    server.close();
  }

  @Test
  public void getForEntity() {
    URI testUri = server.url("/").uri();
    server.enqueue(new MockResponse().setResponseCode(200).setBody("{}"));

    RestTemplate restTemplate = new RestTemplate();

    ResponseEntity<String> forEntity = restTemplate.getForEntity(testUri, String.class);
    assertThat(forEntity.getStatusCode(), is(HttpStatus.OK));
    assertThat(forEntity.getBody(), is("{}"));
  }
}

The following test dependencies are needed:

<dependency>
  <groupId>com.squareup.okhttp3</groupId>
  <artifactId>mockwebserver</artifactId>
  <version>4.2.2</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>com.squareup.okhttp3</groupId>
  <artifactId>okhttp</artifactId>
  <version>4.2.2</version>
  <scope>test</scope>
</dependency>

Upvotes: 1

Related Questions