23
public class ServiceTest {
    @Mock
    RestTemplate restTemplate = new RestTemplate();
    @InjectMocks
    Service service = new Service();
    ResponseEntity responseEntity = mock(ResponseEntity.class);

    @Test
    public void test() throws Exception {
        Mockito.when(restTemplate.getForEntity(
                Mockito.anyString(),
                Matchers.any(Class.class)
                ))
                .thenReturn(responseEntity);
        boolean res = service.isEnabled("something");
        Assert.assertEquals(res, false);
    }

I tried to test a simple test for a service including a restclient. It looks I have not Mock the RestTemplate successfully. It looks like the code get the real data not the mock one. Anyone can help me with this.

The service itself will looks as this:

public class Service{
    public boolean isEnabled(String xxx) {
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.getForEntity("someurl",String.class);
        if(...)return true;
        return false;
    }
}
c2340878
  • 389
  • 1
  • 4
  • 12

3 Answers3

28

The problem is that in your isEnabled you are creating a new RestTemplate. This is wrong for two reasons, one is that you cannot mock it since you are creating a new one, and second it is good to avoid creating new objects per request. RestTemplate is thread safe and hence can be a service class member, being used across many threads.

Change your service class to something like this:

public class Service{

    RestTemplate restTemplate = new RestTemplate();

    public boolean isEnabled(String xxx) {
        ResponseEntity<String> response = restTemplate.getForEntity("someurl",String.class);
        if(...)return true;
        return false;
    }
}

Now that your RestTemplate has become a class member you can now properly mock through one of two ways. One, inject it using the @InjectMock, or use a setter method that you call from your test.

Since you are using InjectMock in your code we can go with that.

@RunWith(MockitoJUnitRunner.class) 
public class ServiceTest {
    @Mock
    RestTemplate restTemplate;
    @InjectMocks
    @Spy
    Service service;
    ResponseEntity responseEntity = mock(ResponseEntity.class);

    @Test
    public void test() throws Exception {
        Mockito.when(restTemplate.getForEntity(
                Mockito.anyString(),
                ArgumentMatchers.any(Class.class)
                ))
                .thenReturn(responseEntity);
        boolean res = service.isEnabled("something");
        Assert.assertEquals(res, false);
    }

Notice that I made a few changes. First, I removed the new RestTemplate() and new Service(). You should let mockito create those for you. By annotating them with @Mock and @Spy you will ensure that Mockito will create them for you, and more importantly, will inject the mocks into your service object.

deworde
  • 2,679
  • 5
  • 32
  • 60
Jose Martinez
  • 11,452
  • 7
  • 53
  • 68
12

Spring MVC's test framework has offered the class MockRestServiceServer for unit testing RESTful service code.

Here is a tutorial on its use.

Keith
  • 3,079
  • 2
  • 17
  • 26
  • I tried the tutorial but it does not work. http://stackoverflow.com/questions/37781982/mocking-a-rest-call-with-mockrestserviceserver – c2340878 Feb 23 '17 at 07:58
3

If you use @Autowired, you could use MockRestServiceServer. The below is the sample.

@Service
public class Service{
    @Autowired
    private RestTemplate restTemplate;

    public boolean isEnabled(String xxx) {
        ResponseEntity<String> response = restTemplate.getForEntity("someurl",String.class);
        if(...)return true;
        return false;
    }
}

@Service needs to use @Autowired for creating object automatically.

hiroyukik
  • 713
  • 1
  • 6
  • 14
  • I tried but it will return the error that restTemplate is null. And it looks I can not inject restTemplate bean. Is there anything else I can do to test it? I just need to mock the response of RestTemplete. – c2340878 Feb 24 '17 at 20:10
  • 1
    Sorry, I missed putting the importance annotation on the class. Please see my answer again. – hiroyukik Feb 24 '17 at 22:31