Reputation: 33
I am new to mockito and need some help, probably some sample on how to mock Rest Template's getForEntity and postForEntity methods. Below is the code for which I want to write Junit test cases by mocking the getForEntity mehod.
SomeService.java
class SomeService
{
//some private, static, final data members
public Map getService(String sNo, String uId, String en)
{
ResponseEntity <Map> response = new
RestTemplate().getForEntity("https://someurl.com/someService",
Map.class);
Map body = response.getBody();
//do something
HttpEntity<?> request = new HttpEntity <>(payLoad, headers);
//payload is Hash Map and headers is a LinkedMultiValueMap
ResponseEntity <Map> response = new RestTemplate().postForEntity(url,
request, headers);
return response.getBody();
}
}
I have tried doing something with @Mock and @InjectMocks.
TestSomeService.java
@RunWith(MockitoJunitRunner.class)
class TestSomeService
{
@Mock
RestTemplate restTemplate;
@InjectMocks
SomeService ser;
/*Some data members*/
@Before
{
HttpEntity <?> request = new HttpEntity<>(reqPayload, headers);
Mockito.when(restTemplate.getForEntity("theUrl",
Map.class)).thenReturn(new ResponseEntity <Map>(someMap,
HttpStatus.OK));
Mockito.when(restTemplate.postForEntity("anotherUrl", request,
Map.class)).thenReturn(new ResponseEntity <Map>(expectedMap,
HttpStatus.OK));
}
@Test
public void testGetService()
{
Map <String, Object> result = ser.getService("123", "abc", "QA");
}
}
Upvotes: 1
Views: 11735
Reputation: 1667
If you are authorized to make changes to SomeService class, I would recommend you to do the following.
class SomeService
{
//some private, static, final data members
public Map getService(String sNo, String uId, String en)
{
ResponseEntity <Map> response = getForEntity("https://someurl.com/someService", Map.class);
Map body = response.getBody();
//do something
HttpEntity<?> request = new HttpEntity <>(payLoad, headers);
//payload is Hash Map and headers is a LinkedMultiValueMap
ResponseEntity <Map> response = postForEntity(url, request, headers);
return response.getBody();
}
}
As you might have guessed getForEntity
and postForEntity
methods have been extracted and RestTemplate is instantiated within – doing its job undercover. And since you wanted to mock RestTemplate from the beginning, it's a good thing we have rid of it – now we can spy on our service without any objects to mock.
@RunWith(MockitoJunitRunner.class)
class TestSomeService
{
@InjectMocks
@Spy
SomeService ser;
/*Some data members*/
@Before
{
HttpEntity <?> request = new HttpEntity<>(reqPayload, headers);
doReturn(new ResponseEntity <Map>(someMap, HttpStatus.OK))
.when(ser).getForEntity("theUrl", Map.class));
doReturn(new ResponseEntity <Map>(expectedMap, HttpStatus.OK))
.when(ser).postForEntity("anotherUrl", request, Map.class));
}
@Test
public void testGetService()
{
Map <String, Object> result = ser.getService("123", "abc", "QA");
}
}
Upvotes: 0
Reputation: 2773
Are you sure that you want to mock especially a restTemplate?
What about not mocking the restTemplate but mocking an answer instead?
It'll help you to test the restTemplate behavior also. What if the restTemplate get 404 or 500?
That's why I suggest you use MockRestServiceServer
It helps to check all realish scenarios.
Upvotes: 0
Reputation: 1829
When you call specific value, you have to wrap it with ArgumentMatchers.eq()
. However, you can use anyString()
, any(Class class)
and other ones as well. They are all self-explanatory. Mockito tutorial.
@Before
public void init (){
MockitoAnnotations.initMocks(this);
HttpEntity <?> request = new HttpEntity<>(reqPayload, headers);
Mockito.when(restTemplate.getForEntity(ArgumentMatchers.eq("theUrl"),ArgumentMatchers.any(Map.class)))
.thenReturn(new ResponseEntity <Map>(someMap, HttpStatus.OK));
}
Regarding to your structure.This way you can inject the RestTemplate
through the constructor.
public class ServiceTester {
@Mock
private RestTemplate restTemplate;
private Service service;
@Before
public void init (){
MockitoAnnotations.initMocks(this);
service = new Service(restTemplate);
HttpEntity <?> request = new HttpEntity<>(reqPayload, headers);
Mockito.when(restTemplate.getForEntity(ArgumentMatchers.eq("theUrl"),ArgumentMatchers.any(Map.class)))
.thenReturn(new ResponseEntity <Map>(someMap, HttpStatus.OK));
}
}
class Service {
private RestTemplate template;
@Autowired
public Service(RestTemplate template) {
this.template = template;
}
public Map doSomething () {
// do something with template
}
}
Upvotes: 2
Reputation: 11757
You have to inject RestTemplate
your service SomeService
. Currently, you're creating a new instance in the service. That means, you don't get the mock instance of RestTemplate
but you get a fresh new instance of the real class RestTemplate
.
You have to do something like this:
class SomeService
{
@Inject
private RestTemplate restTemplate;
//some private, static, final data members
public Map getService(String sNo, String uId, String en)
{
ResponseEntity <Map> response = restTEmplate.getForEntity("https://someurl.com/someService",
Map.class);
...
}
}
Upvotes: 0
Reputation: 92
I mock a rest template like that
@RunWith(SpringRunner.class)
public class Clazz {
@Mock
private RestTemplate restTemplate;
}
So try to use SpringRunner instead of MockitoRunner maybe it will work
Upvotes: 0