I am new to Mockito as well as Spring's RestTemplate. I am working on JUnit tests for a functionality which sends a request to a web-service and gets the response through the use of RestTemplate. I want the server to respond with a response that i want so that i can test the functionalities based on this response. I am using Mockito for mocking.
I am not sure where I am going wrong. Am I not creating proper mocks? Is my JSON object mapper not been configured properly?
Configuration file defining the RestTemplate bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="xsStreamMarshaller" />
<property name="unmarshaller" ref="xsStreamMarshaller" />
</bean>
</list>
</property>
</bean>
<bean id="xsStreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"></bean>
</beans>
My DTO's:
import org.codehaus.jackson.annotate.JsonWriteNullProperties;
@JsonWriteNullProperties(false)
public abstract class BaseDTO {
protected boolean error;
public boolean isError() {
return error;
}
public void setError(boolean error) {
this.error = error;
}
}
public class ChildDTO extends CommercialBaseDTO {
private String fullName;
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
}
Class containing the method to test:
package com.exmpale.mypackage;
import org.springframework.web.client.RestTemplate;
@Component
public class MyUtilClass {
@Autowired
private RestTemplate restTemplate;
public RestTemplate getRestTemplate(){
return restTemplate;
}
public void setRestTemplate(RestTemplate restTemplate){
this.restTemplate = restTemplate;
}
// Method to test
public ChildDTO getChildDTO(MyUser myUser, HttpServletRequest request, HttpServletResponse response)
{
response.setContentType("application/json");
//Nothing much here, it takes the myUser and convert into childDTO
ChildDTO childDTO = new MyUtilClass().getDTOFromUser(request, myUser);
//This is the restTemplate that iam trying to mock.
childDTO = restTemplate.postForObject("http://www.google.com", childDTO, ChildDTO.class);
if (childDTO.isError()) {
//Then do some stuff.........
}
return childDTO;
}
}
The JUnit test class
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"test-config.xml"})
public class MyUtilClassTest {
@InjectMocks
RestTemplate restTemplate= new RestTemplate();
private MockRestServiceServer mockServer;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
//Creating the mock server
//Add message conveters
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new MappingJacksonHttpMessageConverter());
//Create Object mapper
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure( DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure( SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.configure( SerializationConfig.Feature.AUTO_DETECT_FIELDS, true);
objectMapper.configure( SerializationConfig.Feature.AUTO_DETECT_GETTERS,true);
objectMapper.configure( SerializationConfig.Feature.AUTO_DETECT_IS_GETTERS,true);
MappingJacksonHttpMessageConverter jsonMessageConverter = new MappingJacksonHttpMessageConverter();
jsonMessageConverter.setObjectMapper(objectMapper);
messageConverters.add(jsonMessageConverter);
//Set the message converters
restTemplate.setMessageConverters(messageConverters);
mockServer = MockRestServiceServer.createServer(restTemplate);
}
@Test
public void testGetChildDTO()throws Exception {
MyUtilClass myUtil = new MyUtilClass();
MyUser myUser = new MyUser();
HttpServletRequest request = new HttpServletRequestWrapper(new MockHttpServletRequest());
HttpServletResponse response = new HttpServletResponseWrapper(new MockHttpServletResponse());
//create the mocks for ChildDTO. I want MyUtilClass().getDTOFromUser(request, myUser) to return this.
ChildDTO childDTOMock_One = Mockito.mock(ChildDTO);
//Want this to be returned when restTemplate.postForObject() is called.
ChildDTO childDTOMock_Two = Mockito.mock(ChildDTO.class);
childDTOMock_Two.setError(false);
//create the mocks for userMgntUtils
MyUtilClass myUtilClassMock = Mockito.mock(MyUtilClass.class);
//stub the method getDTOFromUser() to return the mock object. I need this mock to be passed to 'postForObject()'
Mockito.when(myUtilClassMock.getDTOFromUser(request, myUser)).thenReturn(childDTOMock_One);
String responseJSON="{\"error\":false}";
//set the expectation values for mockServer
mockServer.expect( requestTo("http://www.google.com")).andExpect(method(HttpMethod.POST)).andRespond(withSuccess(responseJSON,MediaType.APPLICATION_JSON));
//set the expectation values for restTemplate
Mockito.when(restTemplate.postForObject( "http://www.google.com", childDTOMock_One, ChildDTO.class)).thenReturn(childDTOMock_Two);
TypedUserDTO result = userMgmtUtils.getUserProfileDTO(registerUser, request, response, action);
assertNotNull(result);
}
}
Getting the following exception:
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for class org.mockito.internal.stubbing.defaultanswers.GloballyConfiguredAnswer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.biogenidec.dto.TypedUserDTO$$EnhancerByMockitoWithCGLIB$$bee3c447["callbacks"]->org.mockito.internal.creation.MethodInterceptorFilter["handler"]->org.mockito.internal.handler.InvocationNotifierHandler["mockSettings"]->org.mockito.internal.creation.settings.CreationSettings["defaultAnswer"]); nested exception is org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.mockito.internal.stubbing.defaultanswers.GloballyConfiguredAnswer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.biogenidec.dto.TypedUserDTO$$EnhancerByMockitoWithCGLIB$$bee3c447["callbacks"]->org.mockito.internal.creation.MethodInterceptorFilter["handler"]->org.mockito.internal.handler.InvocationNotifierHandler["mockSettings"]->org.mockito.internal.creation.settings.CreationSettings["defaultAnswer"])
And:
Caused by: org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.mockito.internal.stubbing.defaultanswers.GloballyConfiguredAnswer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.biogenidec.dto.TypedUserDTO$$EnhancerByMockitoWithCGLIB$$bee3c447["callbacks"]->org.mockito.internal.creation.MethodInterceptorFilter["handler"]->org.mockito.internal.handler.InvocationNotifierHandler["mockSettings"]->org.mockito.internal.creation.settings.CreationSettings["defaultAnswer"])
The idea of Mockito is to test the class and none of the dependencies outside of it. So if your testing MyUtilClass
you want to mock the RestTemplate
class. And your @InjectMocks is on the wrong class see below.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"test-config.xml"})
public class MyUtilClassTest
{
@Mock
private RestTemplate restTemplate;
@InjectMocks
private MyUtilClass myUtilClass;
@Before
public void setUp() throws Exception
{
MockitoAnnotations.initMocks(this);
}
@Test
public void testGetChildDTO()throws Exception
{
MyUser myUser = new MyUser();
HttpServletRequest request = new HttpServletRequestWrapper(new MockHttpServletRequest());
HttpServletResponse response = new HttpServletResponseWrapper(new MockHttpServletResponse());
Mockito.when(RestTemplate.postForObject(Mockito.eq("http://www.google.com",
Mockito.any(ChildDTO.class), Mockito.eq(ChildDTO.class)))).thenAnswer(
new Answer<ChildDTO>()
{
@Override
public ChildDTO answer(InvocationOnMock invocation) throws Throwable
{
//The below statement takes the second argument passed into the method and returns it
return (ChildDTO) invocation.getArguments()[1];
}
});
ChildDTO childDTO = myUtilClass.getDTOFromUser(request, myUser);
//then verify that the restTemplate.postForObject mock was called with the correct parameters
Mockito.verify(restTemplate, Mockito.times(1)).postForObject(Mockito.eq("http://www.google.com",
Mockito.eq(childDTO), Mockito.eq(ChildDTO.class));
}
}
Also I find it bad practice to test other frameworks classes, more often then not they already tested their class and your just duplicating their work.