I have a question regarding using Mockito thenCallRealMethod. I've read the warnings about using this function; basically I want to write this into my test to futureproof my application logic, because it's being used as a library and I want to make sure users of my library have futureproof protection.
My test case looks like this:
#Test
public void Test() {
when(restTemplate.postForEntity(...)).thenReturn(new ResponseEntity<>(realObjectMapper.writeValueAsString(data), HttpStatus.OK));
when(objectMapper.readValue(realObjectMapper.writeValueAsString(data), TestData.class)).thenCallRealMethod();
TestData result = tested.callMethod(...);
....
}
TestData is a simple POJO which contains a bunch of fields but nothing particularly interesting, and data is an instance of TestData. objectMapper is a mocked instance of FasterXML Jackson ObjectMapper, and realObjectMapper is a real (unmocked) instance of the same class.
The problem I'm having is a NullPointerException when my application attempts to execute objectMapper.readValue (on the mocked instance) as per the thenCallRealMethod on the second line of the test. I've verified that when I pass the same inputs to realObjectMapper.readValue then it executes fine, so there is nothing wrong with the input. What am I missing?
Stack trace:
java.lang.NullPointerException
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2842)
.... (my code here)
When you use a mocked object then the real object is not initialized. That means any property even with a default value will be null.
In my case I had a property injected with #Value from a properties file, but if I define a default value it happens the same, it is null when it is going to be used.
Solution: Yo have to check which is the property causing the null pointer exception on the method and then either mock a getter that returns the expected value of that property and call the getter from your real method or set its value with a setter from the test, after the mock object is created
Related
I am trying to mock a class with Mockito that has a method which chains an interface. The class is mocked successfully but when it calls the interface a null pointer is thrown. The code looks as below:
mock = Mockito.mock(MyProcess.class);
process = mock.getProcess()
.getService() //Interface throwing null exception
.startProcessInstanceByKey("String argument");
I got this solution and tried to follow the example on the page below but its not working: https://static.javadoc.io/org.mockito/mockito-core/2.13.0/org/mockito/Mockito.html#RETURNS_DEEP_STUBS
Foo mock = mock(Foo.class, RETURNS_DEEP_STUBS);
// note that we're stubbing a chain of methods here: getBar().getName()
when(mock.getBar().getName()).thenReturn("deep");
// note that we're chaining method calls: getBar().getName()
assertEquals("deep", mock.getBar().getName());
The example above is not working
You need to mock the retuning Service, too. All external dependencies of you classes need to be mocked and if you doesn´t do this you get null.
processMock = Mockito.mock(MyProcess.class);
serviceMock= Mockito.mock(Service.class);
Mockito.doReturn(serviceMock).when(processMock).getService();
Mockito.doReturn(<VALUE>).when(serviceMock).startProcessInstanceByKey("String argument");
You need to mock every step with external values - this is how it works.
I'm using powermock like so:
DetailServiceImpl impl=PowerMock.createPartialMockForAllMethodsExcept(
DetailServiceImpl.class, "getServiceDetail", JSONObject.class,String.class);
Whitebox.invokeMethod(impl,"getServiceDetail",response,dateFormat.format(date).toString());
However, when this line is run, "getServiceDetail" is executed and a null pointer exception is thrown because the method being mocked on the class DetailServiceImpl uses a class field that is autowired by spring, but on this mock it is null.
By the time I've made this assignment to the variable impl, the method is already run so I can't just do:
impl.setField(myFieldObjMock);
because it's already too late.
How can I fix this issue so that I can either set this field before the method is ran, or have powermock not leave this field null?
____Edit: added WhiteBox call in test in code example_____
I have the following (simplified) function which I wish to check using JUnit:
protected IDfCollection getCollection(IDfSession session) throws DfException{
IDfQuery dfcQuery = new DfQuery();
dfcQuery.setDQL(MY_DQL);
return dfcQuery.execute(session, IDfQuery.READ_QUERY);
}
I have successfully tested it using real IDfSession, but I would like do it without connecting to the repository. So I tried to mock empty IDfSession using:
IDfSession mockedSession = Mockito.mock(IDfSession.class);
But I was given NullPointerException:
Caused by: java.lang.NullPointerException
at java.util.StringTokenizer.<init>(StringTokenizer.java:182)
at java.util.StringTokenizer.<init>(StringTokenizer.java:204)
at com.documentum.fc.internal.util.SoftwareVersion.<init>(SoftwareVersion.java:53)
at com.documentum.fc.client.DfQuery.runQuery(DfQuery.java:136)
at com.documentum.fc.client.DfQuery.execute(DfQuery.java:208)
Not knowing what actually went wrong (which function of the mocked object returned null which was not expected) I created a simple class implementing IDfSession interface and used code coverage tool to check which function was called. I hoped to mock behavior of the function later using mockito. I seemed to be getServerVersion so I changed returned null to real value "6.5.0.355 SP3P0600 Linux.Oracle". Next called function was getBatchManager so I mocked returned object here as well. But now I get:
Caused by: java.lang.ClassCastException: com.example.model.mock.IDfSessionMocked cannot be cast to com.documentum.fc.client.impl.session.ISession
I tried to implement ISession interface in the IDfSessionMocked class, but it does not compile, for instance because one of the used types (namely com.documentum.fc.client.impl.session.ISessionListener) is not visible.
Here: http://www.informedconsulting.nl/blog/?p=187 I found information how to do it using powerMock. Another difference is that object is taken directly from session not using IDfQuery.
What should I do?
Update after comment
getBatchManager function was mocked and now it returns anonymous inner class object, with all the returned values set to false or 0 depending on the expected returned type. Function isFlushBatchOnQuery has been called according to coverage tool.
I am not an expert of Documentum but I think you need a more complex object, you could have a look at this repo https://github.com/ValentinBragaru/dfc-mock
IDfSessionMock is what you need I think.
I hope it helps.
I have a method which does the following as a part of the operation:
URL resourceUrl = new File(sampleString1.concat("/")
.concat(sampleString2)).toURI().toURL();
SampleString1 and SampleString2 are populated by the constructor of the class and the class is an abstract class. I used the below line to test this class:
servlet = PowerMockito.mock(MyServlet.class, Mockito.CALLS_REAL_METHODS);
Through this i'm unable to set values of attributes sampleString1 and sampleString2 as i'm not passing them to constructor. Now, when i call my test method in servlet, i get NullPointerExceptions at the above mentioned line because of null values at sampleString1 and sampleString2. I tried to simulate that part by the following:
PowerMockito.whenNew(File.class).withParameterTypes(String.class).
withArguments(Matchers.anyString()).thenReturn(sampleFile);
but still it goes through the string concatanations when new file call is done and throws exception. How can i test this method? I just want to return a sample value for resourceUrl when new file operation is called and proceed with the logic in the method and test the output.
Thanks.
You can use the Whitebox API documented at the following locations:
http://code.google.com/p/powermock/wiki/BypassEncapsulation
http://powermock.googlecode.com/svn/docs/powermock-1.4.12/apidocs/org/powermock/reflect/Whitebox.html
It uses reflection to set the values on an object like so:
MyServlet servlet = PowerMockito.mock(MyServlet.class, Mockito.CALLS_REAL_METHODS);
Whitebox.setInternalState(servlet, "sampleString1", "foo");
Whitebox.setInternalState(servlet, "sampleString2", "bar");
//Test code...
I have the following interface CatalogVersionService which exposes some services. As well I have a unit test which mocks this interface by using Mockito like this:
CatalogVersionService catalogVersionService = Mockito.mock(CatalogVersionService.class);
And injects the catalogVersionService in a resolver implementation named DefaultClassificationClassResolverService like this:
((DefaultClassificationClassResolverService) ccrservice).setCatalogVersionService(catalogVersionService);
// Assert that my resolver will find a single ClassificationClassModel object
ClassificationClassModel single = new ClassificationClassModel();
assertTrue(ccrservice.resolve(single).contains(single)); //resolver
Up to that point everything works fine until I try to create an integration test and get rid of the Mocked CatalogVersionService interface. As far as I am aware Mockito.mock creates a mock object of given class or interface, in this case CatalogVersionService which is implemented by DefaultCatalogVersionService. So when I try to obtain the real object I do something like this:
catalogVersionService = new DefaultCatalogVersionService();
((DefaultClassificationClassResolverService) ccrservice).setCatalogVersionService(catalogVersionService);
However, after that point is where I get a null pointer exception and my resolver test of course fails. So what does Mockito.mock actually do?? Is it a good approach to assume:
CatalogVersionService catalogVersionService = Mockito.mock(CatalogVersionService.class);
// IS EQUIVALENT TO:
catalogVersionService = new DefaultCatalogVersionService();
Any ideas why the assert is failing?
Thanks in advance
No, it is incorrect to assume that Mockito.mock(...) is the same as instantiating an instance of your DefaultCatalogVersionService. This is not what mocks do.
If you are getting a NullPointerException when using the concrete DefaultCatalogVersionService, this would suggest that something is null within the DefaultCatalogVersionService!
Have you examined the stacktrace to see at what line the NullPointerException occurs, which would help you determine which property/field is null?
It's more than likely that your DefaultCatalogVersionService depends on other classes, which you are not wiring up in your test.