Getting NullpointerException in Mockito - java

I have actual method below:
public ResponseEntity<Message> catEnter(#PathVariable("catId") BigInteger catId, #RequestBody Catrequest catReq, HttpServletRequest request) throws CatDataException, InvalidCatExcecatption {
Message message = new Message();
try {
message = catManager.submitData(catReq.getMessage(), catId, request);
} catch (IOException e) {
throw new CatDataAppException(e.getMessage());
}
return (ResponseEntity<Message>) restResponse(message, request.getMethod());
// Getting null pointer exception in above line
}
I am using mockito for my test code as below:
#Test
public void submitData() throws Exception {
Message mes = new Message();
mes.setCode("00");
mes.setMessage("hi");
ResponseEntity<Message> responseentity = ((ResponseEntity<Message>) catController.catEnter(BigInteger.valueOf(3431), catRequest, mockRequest));
}
I'm getting null pointer exception, Message going as a null, even I set the value explicitly?

Here:
You pass mockRequest when making that call to your production code:
ResponseEntity<Message> responseentity = ... catController.catEnter(... mockRequest));
And your production call does:
return (ResponseEntity<Message>) restResponse(message, request.getMethod());
So the only conclussion: mockRequest is null!
So, first make sure that the passed variable is not null; like:
Request mockedRequest = mock(Request.class);
Or, use the #Mock annotation in case that mockedRequest is a field in your test class.
On top of that; you probably want to do some mock-specification, like:
when(mockedRequest.getMethod()).thenReturn( whatever )
But beyond that, you are lacking a lot of the fundamental basics of Java:
naming conventions: variable names go camelCase, like entityResponse. And typically, tests are named like testCatEnter to express the method that is tested.
You have casts ... where they are not required.
You have quite some code there ... that is unused, like the mes declaration in your test method.
Long story short: I have the feeling that you are overburdening yourself dramatically. First learn the basics; then go for the advanced Mockito stuff.

Related

Handling orElseThrow

My method looks like this
public EP updateEP(long id, EP eP) {
EE eE = eRepo.findById(id).orElseThrow(EntityNotFoundException::new);
//some code
}
and my test method looks like this
#Test
public void testUpdateEWhenEExists() {
long id = 1l;
EE eE = new EE();
eE.setPosId(1l);
eE.setPosName("pos");
EPE ePE = new EPE();
ePE.setEId(id);
when(eRepo.findById(id).orElseThrow(EntityNotFoundException::new)).thenReturn(eE);
//some code
}
And it always throw EntityNotFoundException.I want to be returned to me eE instead of EntityNotFoundException
EDIT
#Test
public void testUpdateEPWhenEExists() {
long id = 1l;
EE eE = new E();
eE.setPositionId(1l);
eE.setPosName("pos");
EPE ePE = new EPE();
ePE.setEId(id);
when(eRepo.findById(id)).thenReturn(Optional.of(eE));
}
In this case error is
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
EPE cannot be returned by findById()
findById() should return Optional
From the code sample you've provided it seems that eRepo.findById(id) returns an Optional.
eRepo.findById(id).orElseThrow(...)
receives that Optional and basically checks, if the Optional is empty. If not, it returns the instance of EE, otherwise it throws the specified exception.
In your test there is no need to call
orElseThrow(EntityNotFoundException::new)
because you're explicitly mocking the behaviour of findById.
Just do it like that:
when(eRepo.findById(id)).thenReturn(Optional.of(eE));
I am posting this to help anyone find this quicker. I needed to assert the message and condition for the exception in a .orElseThrow() from an JPA repository. The normal case is obvious to return Optional.of(someDataYouAlreadyMockedUp), but to get the exception , the repository stream must get a null (Empty) so use Optional.empty() ...
In my code I have
License license = licenseRepository.findById(licenseId).orElseThrow(() ->
new BadRequest("License " + licenseId + " not found."));
To test and assert the value in the Test I mock it like this:
when(licenseRepository.findById(1L)).thenReturn(Optional.empty());
And then call and assert like this:
try {
SomeDto result = someService.getSomeStuffByLicenseId(1L);
fail("should have already thrown exception here!");
}catch (BadRequest br) {
assertEquals("License 1 not found", br.getMessage());
}

Mock in java exception

I have this catch statement:
catch (NotFoundException ex) {
ex.getError().setTitle(NOT_FOUND);
throw new NotFoundException(resource, id, ex.getError());
}
How can I mock this exception? I've tried this
when(service
.filter(eq(any()), eq(any()), eq(any())))
.thenThrow(new NotFoundException(anyString(), anyString()));`
But it gives me a null exception error because of this line:
ex.getError().setTitle(NOT_FOUND);
The constructor is:
public NotFoundException(String resource, String id, Error error) {
this.resource = resource;
this.ids = Collections.singletonList(id);
this.error = error;
}
And I can't get the exception variable to set the title, or find an way to mock it.
Thanks for you help!
.thenThrow(new NotFoundException(anyString(), anyString()));
This isn't allowed: anyString() only stands directly in for the call in when and verify. In your call to filter, simply use any() rather than eq(any()), but you're otherwise using matchers in the correct place.
Furthermore, it looks like your system-under-test assumes that ex.getError() is non-null; it is likely that you'll need to pass in a useful Error instance as constructor parameter into the NotFoundException you create.
.thenThrow(new NotFoundException("foo", "bar", new Error(/* ... */)))
Naturally, if your Error is difficult to create or work with, you might use a mock(Error.class) instead.

Java unit test - exception not being thrown

Trying to write a test that will call my method, when that method makes a call to another method we will throw a custom exception i have made. Here i have simplified it all
2 functions
public MyJsonResponse hello() {
MyJsonResponse response = new MyJsonResponse();
response.setErrorMessage("1");
response.setStatus("some status");
response.setData("1");
response.setHttpResponse(200);
try{
hi();
return response;
}catch (MyServiceException e) {
response.setErrorMessage(e.getMessage());
response.setStatus("error creating");
response.setData("2");
response.setHttpResponse(e.getResponseStatus());
return response;
}
}
public String hi() throws MyServiceException{
LOG.error("Exception");
return "yea";
}
The test I have written is this
#Test
public void myTest() throws Exception {
given(service.hi()).willAnswer( invocation -> { throw new MyServiceException("abc msg",511); });
MyJsonResponse actual = service.hello();
Assert.assertNotNull(actual);
assertEquals(511, actual.getHttpResponse());
}
But unfortunately the result is as follows
java.lang.AssertionError:
Expected :511
Actual :200
Please, be sure that you are using a spy as you want to use the actual code for some methods of your mocked service and just stubbing specific methods of it. Please, see for instance this related SO question about the subject.
Also, consider modifying your test definition to use willThrow instead of willAnswer: as pointed out by #eis, you can still use the later, but the former is more straightforward.
Your code will look similar to this:
#Test
public void myTest() throws Exception {
MyService service = spy(MyService.class);
willThrow(new MyServiceException("abc msg",511))
.given(service)
.hi()
;
// As pointed out by #eis, you can still use willAnswer
// willAnswer(
// invocation -> { throw new MyServiceException("abc msg",511);}
// )
// .given(service)
// .hi()
// ;
MyJsonResponse actual = service.hello();
Assert.assertNotNull(actual);
assertEquals(511, actual.getHttpResponse());
}
regarding what you explain and what your code look like, I am not sure if I have well understood.
Thus, if you want that, your hi() : function throws an exception.
You have to make it first throws an exception. Take a look at code below!
public String hi() throws MyServiceException{
/*LOG.error("Exception");//No don't just log, throw a real exception as below*/
throw new MyServiceException("text here, if your constructor support it or nothing otherwise")
/*return "yea";//Nothing to return? we have just break the code by throwing the exception above*/
}
After that, please be very sure that your 'MyServiceException.getHttpResponse()' will really return 511
For this test to make sense, your hi() call should be done calling another service that you stub/mock in your test class. You're not doing that, so this approach won't work.
You wrote "the real method that hi represents does a lot", so it's about time you extract that to another service.

Mockito :: how to mockSimpleDateFormat.parse() in Dao

I'm new to Java / Mockito and trying to test a Dao method, specifically an exception condition that catches ParseException and throws SQLException.
Here's the Dao code:
public Template saveTemplate(Template template) throws SQLException {
logger.debug("Saving template details into the db ", template.getTemplateName());
SimpleDateFormat dt = new SimpleDateFormat("yyyyy-mm-dd hh:mm:ss");
Long date = 0L;
try {
date = dt.parse(template.getStartTime()).getTime();
} catch (ParseException e) {
throw new SQLException("Error while processing date " + template.getTemplateName());
}
Long finalDate = date;
My strategy was to mock the SimpleDateFormat.parse() call so that it throws the ParseException, but that's not working. Not even sure that's a good strategy...
First I tried:
#InjectMocks private SimpleDateFormat simpleDateformat;
but that doesn't work because the SimpleDateFormat constructor requires a parameter, and gets the error:
org.mockito.exceptions.base.MockitoException:
Cannot instantiate #InjectMocks field named 'simpleDateFormat' of type 'class java.text.SimpleDateFormat'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : null
So then I tried this:
#Mock
private SimpleDateFormat simpleDateFormat;
#Test(expected = SQLException.class)
public void test_save_template_date_parse_error() throws ParseException, SQLException {
initMocks(this);
Mockito.mockingDetails(simpleDateFormat);
Mockito.when(simpleDateFormat.parse(anyString(),new ParsePosition(anyInt()))).thenThrow(new ParseException(anyString(),anyInt()));
Template template = new Template();
template.setStartTime("2017-01-02 12:12:12");
template.setTemplateId(1);
given(jdbcTemplate.getJdbcOperations()).willReturn(jdbcOperations);
templateDAOImpl.saveTemplate(template);
}
The resulting error isn't helpful to my unpracticed eye:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here:
-> at com.macys.etap.ee.dao.TemplateDAOImplTest.test_save_template_date_parse_error(TemplateDAOImplTest.java:77)
-> at com.macys.etap.ee.dao.TemplateDAOImplTest.test_save_template_date_parse_error(TemplateDAOImplTest.java:77)
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last matcher is returning an object
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
So how do I mock this thing and get the error thrown?
Edit: New approach as suggested, mocking Template.getStartTime():
#Test(expected = SQLException.class)
public void test_save_template_date_parse_error() throws ParseException, SQLException {
initMocks(this);
Template templateMock = Mockito.mock(Template.class);
Mockito.when(templateMock.getStartTime()).thenReturn("invalid");
Mockito.mockingDetails(templateMock.getStartTime());
Template template = new Template();
template.setStartTime("2017-01-02 12:12:12");
template.setTemplateId(1);
given(jdbcTemplate.getJdbcOperations()).willReturn(jdbcOperations);
// Fixed per #Daniel Pryden : works now
templateDAOImpl.saveTemplate(templateMock);
}
And now works with the fix.
In my opinion, you don't even need Mockito here, you can simply do the following :
Template template = new Template();
template.setStartTime("THIS IS AN INVALID DATE");
template.setTemplateId(1);
templateDAOImpl.saveTemplate(template);
And then the SQLException will be thrown.
SimpleDateFormat cannot be mocked at all, because you are creating a new instance inside a method, so the mock will be never applied.
Possibilities:
change class structure (e.g put SimpleDateFormat as a constuctor parameter, then InjectMocks annotation will work)
pass invalid data for parse method to break it
use PowerMockito whenNew method, however it should be finality
Mocks aren't magic. They're just objects, and so they obey the same rules as all other objects in the Java language. Most importantly: mock objects don't magically take the place of real objects. You need to pass a reference to the mock instead of a reference to the real object.
In your updated question, you show this code:
Template templateMock = Mockito.mock(Template.class);
Mockito.when(templateMock...)...
Template template = new Template();
...
templateDAOImpl.saveTemplate(template);
That is: you're setting up an object called templateMock which has type Template and is configured with the behavior you want, but then the object you actually pass into templateDAOImpl.saveTemplate is not that object!
This means that all your code setting up the templateMock is effectively dead code: since the value you pass into saveTemplate was constructed using new Template() then it is not a mock.
More generally: Mockito never does anything that you couldn't do by yourself. For example, in this case, you could simply make your own subclass of Template:
private static class FakeTemplate extends Template {
#Override
public String getStartTime() {
return "invalid date";
}
// override other methods as necessary/desired
}
// in your test:
Template fakeTemplate = new FakeTemplate();
templateDAOImpl.saveTemplate(fakeTemplate);
That is all that Mockito is doing when you mock out Template. Mockito just does it in a "fancier" way so that you have less boilerplate code to write. But if you don't understand what Mockito is doing then you shouldn't feel compelled to use it. Always write code you understand, and then you'll always be able to debug it if something goes wrong.
(Aside: There are dirty hacks that can make the new operator instantiate something different than what it was compiled to do -- and that's how PowerMockito does its "magic" -- but that's never necessary and I would never recommend it.)
Just for the record, I found another way to implement this requirement where I used a spy and mocked pretty much everything out; it may help someone else.
#InjectMocks
final Template partiallyMockedTemplate = spy(new Template());
#Test(expected = SQLException.class)
public void test_save_template_date_parse_error() throws SQLException {
initMocks(this);
Template template = new Template();
doReturn("2018-05-44").when(partiallyMockedTemplate).getStartTime();
partiallyMockedTemplate.setStartTime("2017-01-02 12:12:12");
partiallyMockedTemplate.setTemplateId(1);
given(jdbcTemplate.getJdbcOperations()).willReturn(jdbcOperations);
templateDAOImpl.saveTemplate(partiallyMockedTemplate);
}

Testing for a specific exception in MRUnit

In TestNG (or JUnit), it's simple. Goes something like:
#Test(expectedExceptions = NullPointerException)
public void test() throws NullPointerException {
String x = null;
String y = "y";
Assert.assertEquals(x.someMethod(), y);
}
Above test will pass since String x is null and a NullPointerException is thrown.
But in MRUnit, the assertion works differently. Following is a test method for a mapper class:
#Test(expectedExceptions = Data.InvalidDataException.class)
public void testFirstCatch() throws Exception {
Data data = someData;
MapDriver.newMapDriver(mapper)
.withInput(new LongWritable(0), someData)
.withOutput(someKey, NullWritable.get())
.runTest();
It takes an input with someData and expects the output with someKey. But I need to cover a Try/Catch block where it checks for someData's validity by feeding bad data. In this case, it seems like .withOutput method isn't even necessary. Is there a way in MRUnit to conveniently test for Exceptions?
Just had to do .run(); instead of .runTest();. Hope this helps someone.

Categories