Search code examples
javaspringpostmockingresttemplate

How to Mock REST API in unit testing?


I am using RestTemplate exchange HttpMethod.POST method to POST to an endpoint. In my test file I am testing for success of the POST method. However with my current tests I am getting 401 Unauthorized error when POST request is made. I need help to Mock the API while making POST request in test file

Here is my main file


@Component
public class DataTestRepo {

    private final RestTemplate restTemplate;
    private final String url;
    private final AllBuilder headersBuilder;

    public DataTestRepo(
            @Qualifier(Oauth.BEAN_NAME) AllBuilder headersBuilder,
            RestTemplate restTemplate, String url) {
        this.headersBuilder = headersBuilder;
        this.restTemplate = restTemplate;
        this.url = url;
    }
    public ResponseEntity<String> postJson(Set<String> results) {
        ResponseEntity<String> result = null;

        try {
            JSONObject jsonObject = new JSONObject(body);

            HttpEntity<String> request = new HttpEntity<String>(jsonObject.toString(), null);
            restTemplate.getMessageConverters().add(stringConvertor);
            result = restTemplate.exchange(url, HttpMethod.POST,
                    new HttpEntity<>(request, getHttpHeaders()), String.class);
         } 
        return result;
    }
}

Here is my test file

@RunWith(MockitoJUnitRunner.class)
@TestPropertySource
public class DataTestRepoTest {

    private static final String url = "http://localhost:8080/data/name";

    @Mock
    private DataTestRepo DataTestRepo;
    RestTemplate restTemplate = new RestTemplate();

    @Test
    public void restTemplateHttpPost_success() throws URISyntaxException {
        URI uri = new URI(url);
        Set<String> mockData = Stream.of("A","B").collect(Collectors.toSet());
        Map<String, String> body = new HashMap<>();
        body.put("Name", "Aws");
        JSONObject jsonObject = new JSONObject(body);

        HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), null);

        ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.POST,
                new HttpEntity<>(request, DataTestRepo.getHttpHeaders()), String.class);

        Assert.assertEquals(201, result.getStatusCodeValue());
    }
}



Solution

  • You are testing the logic inside DataTestRepo class, so you should not mock it. RestTemplate is a dependency inside DataTestRepo, so this is exactly what you need to mock. In general it should look like this inside your test:

    @InjectMocks
    private DataTestRepo DataTestRepo;
    @Mock
    RestTemplate restTemplate;
    

    Also, you will have to provide a return value for your mocked dependency, like this:

    Mockito.when(restTemplate.exchange(ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn(new ResponseEntity<>(yourExpectedDataHere, HttpStatus.OK));
    enter code here
    

    This is just a simple example. A good practice would be to check that the arguments passed to your mock equal to the expected ones. One way would be to replace ArgumentMatchers.any() with the real expected data. Another is to verify it separately, like this:

    Mockito.verify(restTemplate, Mockito.times(1)).exchange(ArgumentsMatchers.eq(yourExpectedDataHere), ArgumentsMatchers.eq(yourExpectedDataHere), ArgumentsMatchers.eq(yourExpectedDataHere), ArgumentsMatchers.eq(yourExpectedDataHere));