Mock throwing a null pointer exception. New to mockito - java

I'm trying to test the following method
MainClass {
....
Client client;
WebTarget target;
boolean doLogin(MultivaluedMap<String, String> headers) {
client = getRestClient();
target = client.target(BASE_URL))
.path("v1/login");
MultivaluedMap<String, Object> castedHeaders = castMap(headers);//casts headers by entry.
Response loginRsp = target
.request().headers(castedHeaders)
.post(Entity.entity(buildIusLoginEntity(),
MediaType.APPLICATION_JSON_TYPE));
if (loginRsp.getStatus() != HttpServletResponse.SC_OK) {
return false;
}
return true;
}
}
Using the following test class
#Test
public void testdoLoginNegative() {
MainClass m = spy(new MainClass());
Client mockClient = mock(Client.class);
WebTarget target = mock(WebTarget.class);
Response loginRsp = Response.status(500).build();
doReturn(mockClient).when(m).getRestClient();
when(mockClient.target(anyString()).path(anyString())).thenReturn(target);
//NPE on next line.
when(target.request().headers(any(MultivaluedMap.class)).post(any(Entity.class))).thenReturn(loginRsp);// this line throws a Null pointer exception.
Assert.assertFalse(m.doIusLogin(getMockHeaders()));
}
However, my mock seems to show a null pointer exception as indicated in the source code. Any thoughts on what I could be doing wrong.. would be greatly appreciated.

You try to use deep stubbing without preparing your mock objects. Try
WebTarget target = mock(WebTarget.class, Mockito.RETURNS_DEEP_STUBS);
The difference is, that the mock without deep stubbing returns default values on method calls (usually null). If you enclose such a call with Mockito.when this does not have an effect, but if you append further calls this leads to NullPointerExceptions, e.g. in
target
.request() // return null
.headers(any(MultivaluedMap.class)) // NullPointerException
.post(any(Entity.class)))
However I would expect
mockClient
.target(anyString()) // should return null
.path(anyString())) // should throw NullPointerException
to fail too with NullPointerException, without activating deep stubs with
Client mockClient = mock(Client.class, Mockito.RETURNS_DEEP_STUBS);
Not that activating deep stubbing may be convenient for writing tests, but it can lead to strange behaviors in the tested code.

Related

calling method on object returned by when().thenReturn()

After doing lots of research, I didn't find the answer for this question in JUnits in java.
What I want to do is: To call some method on object returned by when().thenReturn(object) call.
e.g.:
public boolean checkUpdate(String str, String endStr){
GetEndpointRequest geaReq = new
GetEndpointRequest().withEndpointArn(endpointArn);
GetEndpointResult geaRes = amazonSNS.getEndpointAttributes(geaReq);
return !geaRes.getAttributes().get("Token").equals(token) || !geaRes.getAttributes().get("Enabled").equalsIgnoreCase("true");
}
And here is the Test method:
import com.amazonaws.services.sns.model.GetEndpointAttributesRequest;
import com.amazonaws.services.sns.model.GetEndpointAttributesResult;
#Tested
AmazonSNSRegistrationService service= new AmazonSNSRegistrationService();
service.amazonSNS = mock(AmazonSNS.class);
#Test
public void checkUpdateTest(){
String pushToken = "dxbv1fwJYIo";
String strToken = "";
String strEnabled = "";
String endPointArn = "";
Map<String, String> jsonBody = new HashMap<String, String>();
jsonBody.put("Token", "");
jsonBody.put("enabled", "");
GetEndpointAttributesRequest getEndpointReq =mock(GetEndpointAttributesRequest.class);
GetEndpointAttributesResult getEndpointRes =mock(GetEndpointAttributesResult.class);
getEndpointRes.setAttributes(jsonBody);
when(service.amazonSNS.getEndpointAttributes(getEndpointReq)).thenReturn(getEndpointRes);
when(getEndpointRes.getAttributes()).thenReturn(jsonBody);
when(getEndpointRes.getAttributes().get(strToken)).thenReturn("");
when(getEndpointRes.getAttributes().get(strEnabled)).thenReturn("");
amazonSNSRegistrationService.checkUpdate(pushToken, endPointArn);
}
I'm getting NullPointerException in checkUpdate() method on line -- "return !geaRes.getAttributes().get("Token").equals(token)".
As, geaRes is null.
How to solve this?
Adding another simple example , where I face this issue:
AmazonSNSRegistrationSerice.java:
public boolean deletePlatformApplicationArn(String deviceId, String appId){
boolean isArnDeleted = false;
try {
DeleteEndpointRequest deleteEndpointReq = new DeleteEndpointRequest().withEndpointArn(appId);
DeleteEndpointResult result = amazonSNS.deleteEndpoint(deleteEndpointReq);
if (result.getSdkHttpMetadata().getHttpStatusCode() == HttpStatus.SC_OK) {
AWSUtil.deleteArnEndpoint(deviceId, appId);
isArnDeleted = true;
}
} catch (Exception e) {
ErrorLogEventHelper.logErrorEvent(this.getClass().getName(), "Exception while deleting AWS ARN (endpoint)" + e.getMessage(), "deletePlatformApplicationArn", e, ErrorLogEvent.ERROR_SEVERITY);
}
return isArnDeleted;
}
AmazonSNSRegistrationSericeTest.java:
#Test
public void deletePlatformApplicationArnTest(){
String appId = "arn:aws:sns";
String deviceId = "dev_1";
DeleteEndpointRequest deleteEndpointReq = mock(DeleteEndpointRequest.class);
DeleteEndpointResult result = mock(DeleteEndpointResult.class);
when(amazonSNSRegistrationService.amazonSNS.deleteEndpoint(deleteEndpointReq)).thenReturn(result);
SdkHttpMetadata metadata = mock(SdkHttpMetadata.class);
when(result.getSdkHttpMetadata()).thenReturn(metadata);
when(result.getSdkHttpMetadata().getHttpStatusCode()).thenReturn(HttpStatus.SC_OK);
amazonSNSRegistrationService.deletePlatformApplicationArn(deviceId, appId);
}
Again the result object in if(result.getSdkHttpMetadata()) is coming NULL.
So first of all, you're trying to get an empty value out of your JsonMap:
#Test
public void checkUpdateTest(){
String strToken = "";
.
.
.
when(getEndpointRes.getAttributes().get(strToken)).thenReturn("");
// so what you ask here is this:
when(getEndpointRes.getAttributes().get("")).thenReturn("");
// this should probably be "Token"
when(getEndpointRes.getAttributes().get("Token")).thenReturn("");
}
the next thing is, the JsonMap is a real object and not a mock so you don't need to call when(getEndpointRes.getAttributes().get(strToken)).thenReturn(""); as your jsonmap is going to return the right value.
then, this call is not needed as your getEndpointRes is a mock. That's why you use the when().thenX() syntax
getEndpointRes.setAttributes(jsonBody);
To resolve your NPE problem try the following:
// imports...
#Tested
AmazonSNSRegistrationService service= new AmazonSNSRegistrationService();
#Test
public void checkUpdateTest(){
// directly mock the amazonsns here
AmazonSNS amazonSNS = mock(AmazonSNS.class);
service.amazonSNS = amazonSNS;
String pushToken = "dxbv1fwJYIo";
String endPointArn = "";
// maybe mock them aswell
Map<String, String> jsonBody = new HashMap<String, String>();
jsonBody.put("Token", "");
jsonBody.put("enabled", "");
// deleted the mocked request. You don't need it in this case as your service contructs it by itself
GetEndpointAttributesResultgetEndpointRes getEndpointRes = mock(GetEndpointAttributesResult.class);
getEndpointRes.setAttributes(jsonBody);
// directly use the mocked object and react on any() as getEntpointReq never will be present in your service!
when(amazonSNS.getEndpointAttributes(any())).thenReturn(getEndpointRes);
when(getEndpointRes.getAttributes()).thenReturn(jsonBody);
amazonSNSRegistrationService.checkUpdate(pushToken, endPointArn);
// do some further assertments
}
It seems that you try to mock things that you don't need to mock and mock things that are generated in your service. If you ever encounter a NPE in the classes you are trying to test you should debug your test properly. In your case the mocking seems incorrect and therefore the real object calls result in NPEs
In your second example it seems to be the same issue. you try to return something from an mock, that is probably created inside your amazonSNSRegistrationService. How should your mocked deleteEndpointReq return any value if it is not part of the class? You simple create the mock, but it is not the same object that is created inside of you service!
And after all you should add some assertions. The tests I see here only fail if the tested class fails with an error like in your case. But some basic assertions are missing. I personally use the AAA pattern for unit tests.

How to test a RestClientException with MockRestServiceServer

While testing a RestClient-Implementation I want to simulate a RestClientException that may be thrown by some RestTemplate-methods in that implementation f.e. the delete-method:
#Override
public ResponseEntity<MyResponseModel> documentDelete(String id) {
template.setErrorHandler(new MyResponseErrorHandler());
ResponseEntity<MyResponseModel> response = null;
try {
String url = baseUrl + "/document/id/{id}";
response = template.exchange(url, DELETE, null, MyResponseModel.class, id);
} catch (RestClientException ex) {
return handleException(ex);
}
return response;
}
How can I achieve this?
I define the mock-server in this way:
#Before
public void setUp() {
mockServer = MockRestServiceServer.createServer(template);
client = new MyRestClient(template, serverUrl + ":" + serverPort);
}
You can test throwing runtime exceptions from the MockRestServiceServer, although this class, as of Spring 5.0.0.RC4, is not designed for it (which means it may not work for more complex use cases):
RestTemplate yourApi;
MockRestServiceServer server = MockRestServiceServer.createServer(yourApi);
server.expect(requestTo("http://..."))
.andRespond((response) -> { throw new ResourceAccessException(
new ConnectException("Connection reset")); });
It seems to work in tests:
where there's only one RestTemplate call,
where the exception is thrown as a result of the last expectation.
I wasn't able to expect two consecutive exceptions; the MockRestSeriviceServer (more concrete, the SimpleRequestExpectationManager) throws IllegalStateException on replaying the second expectation.
You can take advantage of the MockRestResponseCreators for mocking 4xx or 5xx responses from the mockRestServiceServer.
For example for testing a 5xx - Internal server error:
mockServer.expect(requestTo("your.url"))
.andExpect(method(HttpMethod.GET/POST....))
.andRespond(withServerError()...);
In your case the RestClientException is thrown for client-side HTTP errors, so
the example above can be fine tuned for a 4xx exception by using:
...andRespond(withBadRequest()); or ...andRespond(withStatus(HttpStatus.NOT_FOUND));
For a more simpler usage of these methods you use static imports for org.springframework.test.web.client.MockRestServiceServer,org.springframework.test.web.client.response.MockRestResponseCreators
Answer by Alex Ciocan works for different http status responses, so if you want those, go with that as that's the cleanest way to go. I had a problem that I needed to be able to test also for connection reset and other network-level problems, which are trickier to simulate.
Answer by MaDa works for some use cases, but it didn't work for me when using AsyncRestTemplate, as it throws too early. However it did lead me to right direction. This one seems to work with async calls as well:
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
// ...
ClientHttpResponse exceptionThrowingResponse = mock(ClientHttpResponse.class);
when(exceptionThrowingResponse.getStatusCode()) // getRawStatusCode() in latest spring
.thenThrow(new IOException("connection reset"));
mockServer.expect(requestTo("http://localhost:123/callme"))
.andRespond((response) -> exceptionThrowingResponse);
This seems to also work for consecutive exceptions, as well as different http statuses.
How about this :
#Spy
#InjectMocks
ClasstoMock objToMock;
#Test
public void testRestClientException() throws Exception {
try {
Mockito.when(this.objToMock.perform()).thenThrow(new RestClientException("Rest Client Exception"));
this.objToMock.perform();
}
catch(Exception e){
Assert.assertEquals(RestClientException.class, e.getClass());
}

How to mock a method call using Mockito

I have the following problem using Mockito for unit testing:
I have this method:
#Override
public void handle(HttpExchange httpRequest) throws IOException {
Object[] outputResult = processRequest(httpRequest);
String response = (String) outputResult[0];
Integer responseCode = (Integer) outputResult[1];
httpRequest.sendResponseHeaders(responseCode, response.length());
OutputStream os = httpRequest.getResponseBody();
os.write(response.getBytes());
os.close();
}
And I want only to test this method, not the processRequestMethod that is called internally (that I would like to test separately in anthoer test), so I need to mock it and to check at the end of the test that the methods write and close of the OutputStream class have been called.
I have tried two ways, but no luck with none of them:
#Test
public void handleTest() throws IOException {
RequestHandler requestHandler=mock(RequestHandler.class);
String response = "Bad request";
int responseCode = HttpURLConnection.HTTP_BAD_REQUEST;
Object[] result={response,responseCode};
when(requestHandler.processRequest(anyObject())).thenReturn(result);
when (httpExchange.getResponseBody()).thenReturn(outputStream);
requestHandler.handle(httpExchange);
Mockito.verify(outputStream,times(1)).write(anyByte());
Mockito.verify(outputStream,times(1)).close();
}
With the code above, the processRequest method is not called, but neither is the handle method that I want to test, so the test is failing in the line:
Mockito.verify(outputStream,times(1)).write(anyByte());
Saying that this method was not called at all.
However if I add the parameter CALL_REAL_METHODS when creating the mock, like this:
#Test
public void handleTest() throws IOException {
RequestHandler requestHandler=mock(RequestHandler.class,CALLS_REAL_METHODS);
String response = "Bad request";
int responseCode = HttpURLConnection.HTTP_BAD_REQUEST;
Object[] result={response,responseCode};
when(requestHandler.processRequest(anyObject())).thenReturn(result);
when (httpExchange.getResponseBody()).thenReturn(outputStream);
requestHandler.handle(httpExchange);
Mockito.verify(outputStream,times(1)).write(anyByte());
Mockito.verify(outputStream,times(1)).close();
}
Then the processRequest method that I want to skip is actually called when the method executes this line:
when(requestHandler.processRequest(anyObject())).thenReturn(result);
Any clues of what can be wrong?
in your test instead of
RequestHandler requestHandler=mock(RequestHandler.class,CALLS_REAL_METHODS);
use Mockito.spy():
RequestHandler requestHandler=spy(RequestHandler.class);
doReturn(result).when(requestHandler).processRequest(httpRequest);
you may want the doReturn().when() form rather than the when().thenReturn() because the first does not execute the method whereas the latter does.
On the other hand I'd prefer to move processRequest() to another class where you can inject an instance of into RequestHandler which would make mocking more straight...

Powermockito/Java - Spying class under test to verify private method call

I'm writing unit tests in java using Mockito/PowerMockito, but on the test I'm working on, I can't get rid of this UnfinishedStubbingException.
The method I'm trying to test is private, so I use WhiteBoxImpl to invoke the method. Inside the method I invoke, a call is potentially made to another private method (call it pm2) in the class under test. I want to verify that pm2 is never called, so I make a spy for the class under test, and verify pm2 is never() called.
So far, this test has always thrown an UnfinishedStubbingException, but I can't figure out what part of my test Powermockito doesn't like. I have another (working) test that operates very similarly, except I don't need to verify the behavior of a method like pm2. So in this working case, I don't need to create a spy for the class under test. I believe my issue is somehow related to the spy, but I don't know of a way to test what I'm trying to test without it.
Here's what I have right now:
#Mock(name = "BO")
BO BOMock;
#Mock(name = "DAO")
DAOI DAOMock;
#InjectMocks
ServiceImpl service;
#Test
public void unitTest(){
MessageObject msg = new MessageObject();
Record recordMock = mock(Record.class);
MetaData metaDataMock = mock(MetaData.class);
doNothing().when(DAOMock).doAction(any(Param1.class), anyInt());
when(DAOMock.doOtherAction(any(Param1.class), eq(msg.getId()))).thenReturn(recordMock);
when(BOMock.getMetaData(anyInt(), anyInt()).thenReturn(metaDataMock);
ServiceImpl spy = PowerMockito.spy(this.service);
PowerMockito.doReturn(new Long(10)).when(spy, "checkDelay", recordMock, msg, metaDataMock);
Whitebox.invokeMethod(spy, "process", msg);
verify(recordMock, never()).getStatus();
}
Here's the method in the class ServiceImpl that I'm testing:
private BO BO = new BO();
private DAOI DAO = new DAO();
private void process(Message msg) {
try {
DAO.doAction(new Param1.class, msg.getId());
} catch(Exception e) {
logger.error("some message");
return;
}
Record record = null;
try {
int intParam1 = msg.getId();
int intParam2 = msg.getDifferentId();
MetaData metaData = BO.getMetaData(intParam1, intParam2);
record = DAO.loadRecord(new Param1(), msg.getId());
// checkDelay is a private method in ServiceImpl.java
long delayForMinutes = checkDelay(record, msg, metaData);
if(delayForMinutes > 0) {
// Control should reach here
logger.debug("some message");
return;
}
// Control should not reach here
if(Record != null && Record.getStatus() != CREATED) {
logger.debug("some message");
return;
}
// Perform various actions
} catch(Exception e) {
// Perform other various actions
}
}
When I run this test I get an UnfinishedStubbingException. The line at the top of the stack trace is:
DAO.doAction(new Param1.class, msg.getId());
The error message provides the following hints:
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
But I can't seem to figure out how any of them apply to my situation. Does anyone know what's going on behind the scenes to cause this error?
Thank you
The problem line is
when(DAOMock.doOtherAction(any(Param1.class), eq(msg.getId()))).loadRecord(recordMock);
You don't seem to have a then, thenReturn or thenThrow here. You always need to use one of those with when.

Capturing parameters of a method at runtime in Java

Our application uses several back-end services and we maintain wrappers which contain the methods to make the actual service calls. If any exception occurs in any of those methods while invoking a service, we throw a custom exception encapsulating the original exception as shown below.
interface IServiceA {
public void submit(String user, String attributes);
}
public class ServiceAWrapper implements IserviceA {
private ActualService getActualService() {
.....
}
public void submit(String user, String attributes) {
try {
Request request = new Request();
request.setUser(user);
request.setAttributes(attributes);
getActualService().call(request);
} catch(ServiceException1 e) {
throw new MyException(e, reason1);
} catch(ServiceException2 e) {
throw new MyException(e, reason2);
}
}
}
I would like to know if there's any framework that would allow me to
capture (and probably log) all the
parameters passed to my wrapper
methods at run-time; if the methods
are called.
capture the actual exception
object(MyException instance in above
example), if any thrown; so that I
could append the passed parameters
to the object at run-time.
I am currently exploring AspectJ to see if it can address my requirements, but I am not sure if it can be used to capture the parameters passed to methods at runtime and also to capture exception objects, if any occur.
Thanks.
With AspectJ, you can use around advice to execute advice instead of the code at the join point. You can then execute the actual join-point from within the advice by calling proceed. This would allow you to capture the input parameters, log them, and proceed to call the actual method.
Within the same advice you could capture any logs throw from the method, and inspect or log them before passing it back up to higher levels.
Matt B's answer is right. Specifically, you can do something like this:
aspect MonitorServiceCalls {
private final Logger LOG = LoggerFactory.getLog("ServiceCallLog");
Object around() throws MyException: call(public * *(..) throws MyException)
&& target(IServiceA+) {
MethodSignature msig = (MethodSignature)thisJoinPoint;
String fullMethName = msig.getMethod().toString();
try {
Object result = proceed();
LOG.info("Successful call to {} with arguments {}",
fullMethName,
thisJoinPoint.getArgs());
return result;
} catch(MyException e) {
LOG.warn("MyException thrown from {}: {}", msig.getMethod(), e);
throw e;
}
}
}
AspectJ is the right option. You will be able to get hold of the parameters by way of a JoinPoint object that will be passed to your advise methods. You can also get hold of the exception either by implementing an after throwing advise or an around advise.

Categories

Resources