I am trying to mock RequestContext and HttpServletRequest classes/interfaces but they not working.
code:
#Override
public Object run() {
String accessToken= "";
ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String requestedServiceUri = request.getRequestURI();
//...
Mock I have written
//...
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
RequestContext requestContext = Mockito.mock(RequestContext.class);
when(request.getHeader("principal")).thenReturn("abcd");
when(request.getHeader("authorization")).thenReturn("authtoken");
when(request.getRequestURI()).thenReturn("abcd-tt/api/v1/softwaremanagement");
when(requestContext.getCurrentContext()).thenReturn(requestContext);
when(requestContext.getRequest()).thenReturn(request);
//...
I am getting MissingMethodInvocation exception. Not sure if this right way of testing this method
Need to mock the static call for the context.
//Arrange
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
when(request.getHeader("principal")).thenReturn("abcd");
when(request.getHeader("authorization")).thenReturn("authtoken");
when(request.getRequestURI()).thenReturn("abcd-tt/api/v1/softwaremanagement");
RequestContext requestContext = Mockito.mock(RequestContext.class);
when(requestContext.getRequest()).thenReturn(request);
PowerMockito.mockStatic(RequestContext.class);
when(RequestContext.getCurrentContext()).thenReturn(requestContext);
Do not forget to include
#PrepareForTest(RequestContext.class)
so that the mocked static calls will be available when invoked.
Related
I have a service class, with for readability purpose, I have provided the code with dummy variables and objects. I am trying to write a JUNIT test class for the service, primarily with Mockito. No matter how hard I try, I am not able to hit the method serviceMethod irrespective of using spy/mock. I have also included a test, following the main class.
I know I am missing something here, but doesn't cross my mind. I need an eye to review this and let me know how I can write a proper test class for this and obtain coverage for the method.
(P.S. all the necessary imports are in-place and not pasted here to keep this concise)
Thanks in advance!
#Service
public class ServiceClass {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceClass.class);
#Autowired
String stringUrl;
RestTemplate restTemplate = new RestTemplate();
public void serviceMethod(ModelObject model) {
try {
HttpEntity<ModelObject> request = new HttpEntity<>(model);
ResponseEntity<String> response = restTemplate.exchange(stringUrl,
HttpMethod.POST, request, String.class);
LOGGER.info(response.getBody() + "and " + response.getStatusCode());
} catch (HttpClientErrorException exception) {
LOGGER.info(exception.getResponseBodyAsString());
} catch (HttpStatusCodeException exception) {
LOGGER.info(exception.getResponseBodyAsString());
}
}
Sample Test:
#RunWith(MockitoJUnitRunner.Silent.class)
public class ServiceClassTest {
#InjectMocks
private ServiceClass serviceClass;
#Mock
private RestTemplate restTemplate;
#Test
public void testServiceMethod() {
ServiceClass spy = Mockito.spy(serviceClass);
// ServiceClass spy = mock(ServiceClass.class, Mockito.CALLS_REAL_METHODS);
doNothing().when(spy).serviceMethod(Mockito.any(ModelObject.class));
Mockito.doCallRealMethod().when(spy).serviceMethod(Mockito.any(ModelObject.class));
ResponseEntity<String> responseEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
Mockito.when(restTemplate.exchange(ArgumentMatchers.anyString(), ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.<HttpEntity<ModelObject>>any(), ArgumentMatchers.<Class<String>>any()))
.thenReturn(responseEntity);
}
In my Springboot-Controller my Requestmapping method should support flexible subdirectory names. For that I like to use real regexpression. I have tested my regex and it works fine outside of SpringBoot and RequestMapping, however on top of RequestMapping it does not work.
If any http-requests gets in with
http://dir1 or http://dir2
my Method getFile should be called, but it doesn't.
#RequestMapping(value = "{reg:\\/(dir1|dir2)+}", method = RequestMethod.GET)
public void getFile(HttpServletResponse response, HttpServletRequest requ) throws IOException {
}
My question is how to accomplish this ....
The regex-based #RequestHandler can be achieved through (for more)
#RequestMapping(value = "{reg:regexPattern}", method = RequestMethod.GET)
public void getFile(HttpServletRequest request, HttpServletResponse response,
#PathVariable String reg) throws IOException {
...
}
But in your case, the regex pattern is a directory value that contains Slash("/") makes request handler difficult to find the exact mapping. Instead of #PathVariable, you can use #RequestParam
#RequestMapping(value = "\", method = RequestMethod.GET)
public void getFile(HttpServletRequest request, HttpServletResponse response,
#RequestParam("dir") String dir) throws IOException {
...
}
The solution is (Dirk Deyne gave me the hint) that the Slashes have to be outside the regexpression. Here is the solution, where I have extended the value with another subdir filedir to make it more clear:
#RequestMapping(value = "/{subdir:[dir1|dir2]+}/filedir", method = RequestMethod.GET)
public void getFile(HttpServletResponse response, HttpServletRequest requ) {
...
}
This will serve the following incoming requests:
http://localhost:8080/dir1/filedir
http://localhost:8080/dir2/filedir
Thank you!
From the service I call the third party api using RestTemplate.
#RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {
#InjectMocks
private ForceService forceService;
#Mock
private RestTemplate restTemplate;
#Before
public void setup() {
forceService = new ForceService(config, restTemplate);
}
#Test
public void createTest_valid() throws JSONException {
/*Mockito.when(restTemplate.exchange(url, HttpMethod.POST, entity, CreateRecordResult.class))
.thenReturn(response);*/
Mockito.verify(restTemplate, Mockito.times(1))
.exchange(Mockito.anyString(),
Mockito.<HttpMethod> any(),
Mockito.<HttpEntity<?>> any(),
Mockito.<Class<?>> any());
forceService.createLead(lead);
}
}
I tried using both the any() method and directly specifying the values. Directly specifying the value in entity seems to be not the right way to test.
Below is the service class that I need to write test cases for.
#Component
public class ForceService {
private RestTemplate restTemplate;
public ForceService(ForceServiceConfig config, RestTemplate restTemplate) {
this.config = config;
this.restTemplate = restTemplate;
}
public String createLead(Lead lead) {
HttpHeaders headers = new HttpHeaders();
headers.set(AUTHORIZATION, getAccessToken());
headers.set(ACCEPT, APPLICATION_JSON);
headers.set(CONTENT_TYPE, APPLICATION_JSON);
LeadWrap leadWrap = new LeadWrap();
leadWrap.setFirstName(lead.getFirstName());
leadWrap.setLastName(lead.getLastName());
leadWrap.setEmail(lead.getEmail());
leadWrap.setPhone(lead.getPhone());
String jsonString;
try {
jsonString = new ObjectMapper().writeValueAsString(leadWrap);
} catch (IOException e) {
throw new RuntimeException(e);
}
HttpEntity<String> entity = new HttpEntity<>(jsonString, headers);
ResponseEntity<CreateRecordResult> exchange = restTemplate.exchange(
config.restUrl + "/v" + config.restVersion + "/sobjects/Lead/", HttpMethod.POST, entity,
CreateRecordResult.class);
if (exchange.getStatusCode().equals(HttpStatus.CREATED)) {
if (exchange.getBody() != null && exchange.getBody().success) {
LOGGER.info("Lead record created with Id " + exchange.getBody().id);
return exchange.getBody().id;
}
throw new RuntimeException("Record is not created");
} else {
LOGGER.error(RETURN_STATUS + exchange.getStatusCode());
throw new RuntimeException(RETURN_STATUS + exchange.getStatusCode());
}
The above test case returns the ResponseEntity exchange as null. Is there any solution for this to make the test case work for RestTemplate exchange call?
The verify needs to go after the call to the production code, in your case the createLead() call. You also are going to want to use matchers for your when call, which probably shouldn't be commented out. In cases like yours you generally don't need both the when and the verify. It just makes the test more complex and harder to read.
I use the verify if there is no return from the service call that I can assert on. In those cases I would wrap all the parameters of the when (if needed to get past a null pointer exception or other error) in any() such as any(HttpEntity.class) or anyString() so the params aren't ambiguous. Then you can use the verify to confirm the actual params are correct. This strategy is easier to maintain. Unfortunately, often it requires an argument captor to verify headers or other params are sent correctly. I say it's unfortunate because the tests become big and messy,
If I can assert on the result I often just use the when. In that case I would wrap the params with eq(), such as eq(httpEntity). In that case the HttpEntity class would need to have a good .equals() method or it would just use the default and probably isn't very helpful. But, it is generally pretty powerful.
You shouldn't use #InjectMocks and initialize in the setup. If you #InjectMocks it creates the instance and injects the mocks. You seem to wan to put a real config in so you would use the setup method or you could mock the config. I used a correct matcher, but you might have to refine them, for example switch some any() to eq() to truly test what you want to test. I also reordered so the action or the call to production call is before the verify. This test should get you started.
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
#RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {
private ForceService forceService;
#Mock
private RestTemplate restTemplate;
#Before
public void setup() {
forceService = new ForceService(new ForceServiceConfig(), restTemplate);
}
#Test
public void createTest_valid() throws Exception {
when(restTemplate.exchange(anyString(), eq(HttpMethod.POST),
any(HttpEntity.class),
eq(CreateRecordResult.class)))
.thenReturn(new ResponseEntity<>(new CreateRecordResult(), HttpStatus.CREATED));
forceService.createLead();
verify(restTemplate, times(1))
.exchange(eq("config.restUrl/vconfig.restVersion/sobjects/Lead/"),
any(HttpMethod.class),
any(HttpEntity.class),
eq(CreateRecordResult.class));
}
}
You need to tell Mockito what to return when the mock is called...
when(restTemplate.exchange(anyString(), any(), any(), any())).thenReturn(...
Insert the responseEntity you want returned from the call to exchange in the thenReturn.
#DCTID code saved my day. Along with that I faced the below issue and fixed it.
To mock the ResponseEntity's body, I created an object and set value to it. Else, it was not passing this condition - if (exchange.getBody() != null && exchange.getBody().success)
CreateRecordResult createRecordResult = new CreateRecordResult();
createRecordResult.success = true;
Mockito.when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class),
eq(CreateRecordResult.class)))
.thenReturn(new ResponseEntity<>(createRecordResult, HttpStatus.CREATED));
Well this is the setup that I have:
WelcomeUser.java
package org.user.www.action;
import org.user.www.dao.ApplicationDAOfactory;
import org.user.www.dao.UserPojoDao;
import org.user.www.pojo.UserPojo;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class WelcomeUser extends ActionSupport implements ModelDriven<UserPojo> {
private static final long serialVersionUID = 1L;
private UserPojo userPojo = new UserPojo();
private ApplicationDAOfactory appFactory = new ApplicationDAOfactory();
private UserPojoDao appDAOObj /*= ApplicationDAOfactory.getUserPojoDaoInstance()*/;
public WelcomeUser(){
}
public WelcomeUser(UserPojoDao appDAOObj, ApplicationDAOfactory appFactory){
this.appDAOObj = appDAOObj;
this.appFactory = appFactory;
}
public String execute(){
return SUCCESS;
}
#Override
public UserPojo getModel() {
// TODO Auto-generated method stub
return userPojo;
}
public String welcome(){
appDAOObj = appFactory.getUserPojoDaoInstance();
appDAOObj.persistUser(userPojo);
return SUCCESS;
}
}
ApplicationDAOfactory.java
package org.user.www.dao;
public class ApplicationDAOfactory {
public UserPojoDao getUserPojoDaoInstance(){
return new UserPojoDaoImpl();
}
}
WelcomeUserTest.java
package org.user.www.junit;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.Map;
import org.apache.struts2.StrutsJUnit4TestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.user.www.action.WelcomeUser;
import org.user.www.dao.ApplicationDAOfactory;
import org.user.www.dao.UserPojoDao;
import org.user.www.dao.UserPojoDaoImpl;
import org.user.www.pojo.UserPojo;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionProxy;
#RunWith(MockitoJUnitRunner.class)
public class WelcomeUserTest extends StrutsJUnit4TestCase<WelcomeUser>{
#Mock private UserPojoDao appDAOObj;
#Mock private ApplicationDAOfactory appFactory;
#Mock private UserPojo userPojo;
#Before
public void setUpBeforeClass() throws Exception {
appDAOObj = mock(UserPojoDaoImpl.class);
appFactory = mock(ApplicationDAOfactory.class);
//MockitoAnnotations.initMocks(WelcomeUser.class);
new WelcomeUser(appDAOObj, appFactory);
}
#Test
public void testWelcome() throws Exception{
when(appFactory.getUserPojoDaoInstance()).thenReturn(appDAOObj);
when(appDAOObj.persistUser(userPojo)).thenReturn(userPojo);
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("name" ,"user");
paramMap.put("email" ,"user#user.com");
ActionProxy proxy = getActionProxy("/submitUser");
ActionContext actionContext= proxy.getInvocation().getInvocationContext();
actionContext.setParameters(paramMap);
String result= proxy.execute();
assertEquals("success", result);
}
}
My doubt is that although I am trying to mock the behavior upon which my welcome method in the struts action class depends but it doesn't seems to be working. I have browsed through various sources but it has all gone in vain. As far as I have been able to comprehend this situation my best guess is that when I call the execute method upon the proxy instance in my test method the control does execute the welcome method as per the mapping in my struts.xml file but when execution arrives at the point where I am expecting my mocks to work it doesn't works and hits my database which I don't want. I do understand there is certainly a gap in my understanding but any help shall be appreciated. Cheers!!
I had similar issue but my case was bit different as I was using setter Injector through spring framework and my action class already had setter method for Dao.
I had to get the action from proxy and Inject mocked Dao object into my action.
I did following before executing proxy :
WelcomeUser actionObj = (WelcomeUser) proxy.getAction();
actionObj.setDaoObj(appDAOObj);
you have to figure out a way to inject mocked objects into actionObj .
Update :
Check if following works for you
WelcomeUser actionObj = (WelcomeUser) proxy.getAction();
ReflectionTestUtils.setField(actionObj, "appDAOObj", appDAOObj);
ReflectionTestUtils.setField(actionObj, "appFactory", appFactory);
String result= proxy.execute();
assertEquals("success", result);
Make sure you have spring-test-x.x.x.RELEASE.jar and spring-core-x.x.x.RELEASE.jar (Including any other dependency) in your classpath.
I have a very different kind of method call which I need to test using JMockit testing framework. First let us look at the code.
public class MyClass{
MyPort port;
public registerMethod(){
Holder<String> status=null;
Holder<String> message=null;
//below method call is a call to a webservice in the real implementation using apache cxf framework. This method has a void return type. Read below for better explanation.
port.registerService("name", "country", "email", status, message);
// do some stuff with status and message here.....
HashMap response = new HashMap();
response.put(status);
response.put(message);
return response;
}
}
Now let me explain the a little bit. This class is basically having a port instance variable which is used to connect to a webservice. The webservice implementation uses auto generated apache cxf framework classes to make connection to the webservice and get the response back. My job is to implement the mocking of this webservice call for writing testcases for lot many similar calls that are there in the real application.
The problem here is - If you notice that call to the webservice is actually made by the method port.registerService by sending name, country and email as the parameters. Now we also pass the status and message variables as the parameters themselves to this method. So this method instead of returning some value for status and message, it FILLS IN values in these two passed parameters which is very different from the "RETURN" approach.
Now the problem is when I m trying to mock this call using jmockit, I can always mock this call but what is to be expected ?? as there is no return at all, it turns out to be a void call which fills in values in the parameters passed to it. So I will always get status, and message as null if I mock this call as I cannot state any return expectation in the jmockit implementation.
Please if anybody has any solutions/suggestions to the above problem, do respond and try to help me. Thanks.
I was not sure what the Holder interface looked like so I made some assumptions. But, this is how you mock a method with a void return type using Mockito:
#SuppressWarnings("unchecked")
#Test
public final void test() {
// given
final String expectedStatus = "status";
final String expectedMessage = "message";
final MyPort mockPort = mock(MyPort.class);
final Answer<Void> registerAnswer = new Answer<Void>() { // actual parameter type doesn't matter because it's a void method
public Void answer(final InvocationOnMock invocation) throws Throwable {
// Here I'm stubbing out the behaviour of registerService
final Object[] arguments = invocation.getArguments();
// I don't actually care about these, but if you wanted the other parameters, this is how you would get them
// if you wanted to, you could perform assertions on them
final String name = (String) arguments[0];
final String country = (String) arguments[1];
final String email = (String) arguments[2];
final Holder<String> statusHolder = (Holder<String>) arguments[3];
final Holder<String> messageHolder = (Holder<String>) arguments[4];
statusHolder.put(expectedStatus);
messageHolder.put(expectedMessage);
// even though it's a void method, we need to return something
return null;
}
};
doAnswer(registerAnswer).when(mockPort).registerService(anyString(),
anyString(), anyString(), any(Holder.class), any(Holder.class));
final MyClass object = new MyClass();
object.port = mockPort;
// when
final Map<String, String> result = object.registerMethod();
// then
assertEquals(expectedStatus, result.get("status"));
assertEquals(expectedMessage, result.get("message"));
}
For reference, these are my imports:
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;