Mock Documentum IDfSession using Mockito - java

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.

Related

How to mock a repository method no matter the parameters with mockito

I'm using spring framework and testing with Junit and mockito.
Right now I have a method in my service which is using a few objects I create in the test, let's call them configObject1 and configObject2, I send them to the method as a parameter, and then the method start making some calls to another repositories along those configuration objects, those repositories are mocked and work well, the method makes a List of "CalculusResult" from those queries/configObjects. After that I use a repository extending CRUDRepository and make a saveAll(). Then it should return an iterable with the entities, but for some reason after the saveAll method it returns an empty list.
Test:
#Test
...
configObject1 conf1 = new configObject1 (...);
configObject2 conf2 = new configObject2 (...);
Calculusresult calcRes = new CalculusResult(null,...,new java.sql.Date(system.currentTimeMilis()),...);
List<CalculusResult> resList= new ArrayList<CalculusResult>();
resList.add(calcRes);
Calculusresult calcRes2 = new CalculusResult(1,...,new java.sql.Date(system.currentTimeMilis()),...);
List<CalculusResult> resList2= new ArrayList<CalculusResult>();
resList2.add(calcRes2);
when(calculusResultRepository.saveAll(resList)).thenReturn(resList2);
...
assertTrue(!response.isEmpty())
Method from the service:
...//The method is building the list of calculusResults
resCalc.setDate(new java.sql.Date(system.currentTimeMilis()))
resList.add(calcres);//CalculusResult object is added to the list, this object is well made
List<CalculusResult> savedResults = (List<CalculusResult>) calculusResultRepository.saveAll(resList); //This returns an empty list (If I don't cast, it also returns nothing)
for(CalculusResult calcres : savedResults){
... //This makes nothing because savedResults is empty, making the response empty and failing the test.
Repository:
#Repository
public interface CalculusResultRepository extends CrudRepository<CalculusResult, Long> {
}
I'm not sure but I think the problem may be that the object I'm creating in the test is different to the one in the service because one of the attributes is an sql Date of the moment it's created, so maybe it's not triggering "when(calculusRepository.saveAll(reslist)..." in the test because the object created in the test and the one created in the service have different Dates in that atribute.
If that's the case, is there a way to fix it? Or is the problem a completely different thing?
You can use Mockito ArgumentMatchers to match any argument.
when(calculusResultRepository.saveAll(Mockito.any(List.class)))
.thenReturn(resList2);

Integration Test for methods with no returning value in Java

I am trying to build an integration test method in Java, but there are some service methods that have no returning value (void). So, in this scene, normally I would create a record and then retrieve this record using the id of created record. However, as there is no returned value, how can I write integration test for example such a kind of service method? Is that possible?
public void saveProperties(final Request request, final UUID productUuid) {
repository.saveProduct(request, productUuid);
}
You can actually verify the service method was called or not using Mockito.verify.
Sample usage:
Mockito.verify(mockedObject, Mockito.times(1)).saveProduct(any(Request.class), any(UUID.class));
This will validate that the saveProduct was called on your mocked object.

Mockito mock calls actual implementation when not told to

I have a class which contains the following three methods:
void add(Service... objs)
void add(Collection<Service> objs)
void add(Stream<Service> objs)
As you might expect, these all support the adding of zero or more objects, which can be specified individually or as part of an array, a collection or a stream. The first two variants create a stream from their arguments, and pass them to the third variant which actually does the adding.
In testing an object that uses this class, I have created a Mockito mock object to represent an instance of this class, using Spring's #MockBean annotation. I can see in the debugger that the object under test contains the mock object, and that the call I am expecting (with a single argument of type Service) is being addressed to the mock. Because the method that should be called is the first variant (the varargs one), and I know that varargs parameters are a little tricky, I coded the test to check that the mock is called with the correct parameter as follows:
ArgumentCaptor<Service> captor = ArgumentCaptor.forClass(Service.class);
verify(theMock).add(captor.capture());
assertThat(captor.getAllValues()).containsExactly(expectedService);
However, when I run this code the assertion fails because the List returned by captor.getAllValues() contains not a Service, but a Stream: the failure message says:
java.lang.AssertionError:
Expecting:
<[java.util.stream.ReferencePipeline$Head#2cfe272f]>
to contain exactly (and in same order):
<[com.xxx.data.Service#37c5]>
but some elements were not found:
<[com.xxx.data.Service#37c5]>
and others were not expected:
<[java.util.stream.ReferencePipeline$Head#2cfe272f]>
When I run the code in the debugger, I can see that the call from the object under test to add(Service...) invokes the real implementation; this invokes add(Stream<Service>) and it is that call which is intercepted by the mock. That explains why I am seeing the failure, but I don't understand why the mock is failing to intercept the original call, or what I can do to make it do so.
Update your ArgumentCaptor to accept Service[]
ArgumentCaptor<Service[]> serviceCaptor = ArgumentCaptor.forClass(Service[].class);
And assert
Service[] actualServices = serviceCaptor.getAllValues();
assertEquals(actualServices.length, 1);
assertEquals(actualServices[0], service);
And it's best practice to use ErrorCollector in Junit to assert more than one
assert and SoftAssect in Testng and call after your assertion softAssert.assertAll()
I have come up with a workaround to the problem, but the actual problem still exists and I think it is probably a Mockito bug (raised as https://github.com/mockito/mockito/issues/1929).
The workaround is to add this method to my test class. I've added a generic method because it is not just a call to the add() method that has the problem, but also a call to a similar overloaded remove() method that takes String arguments.
private <T, V> void verifyCall(T mock, BiConsumer<T, V> call,
V expectedArg, Class<V> type)
{
ArgumentCaptor<V> captor = ArgumentCaptor.forClass(type);
call.accept(verify(mock), captor.capture());
List<?> values = captor.getAllValues();
try {
assertThat(values.get(0)).isEqualTo(expectedArg);
} catch (AssertionFailedError ex) {
assertThat((Stream<V>) values.get(0)).containsExactly(expectedArg);
}
}
This should work whether the call intercepted by the mock was to the varargs variant of the method (as it should be) - in which case the assertion in the body of the try block will not throw an exception - or to the Stream variant (as it currently is) - in which case the assertion in the body will throw an exception and the assertion in the catch block will be executed.
Then, when I want to verify that my mock's add() method was called with the expected Service object, I do so with:
verifyCall(theMock, Datastore::add, expectedService, Service.class);
And similarly, for the remove() method:
verifyCall(theMock, Datastore::remove, expectedDeletedKey, String.class);
Very pleasingly, when I finally got this working the test failed because I had made a mistake in the method under test. Which made it all worthwhile.
D'oh. I failed to spot that the two varargs methods were declared as final. Removed this and it all works as expected.

NullPointerException when using Mockito thenCallRealMethod

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

mockito - how to check an instance inside a method

I am new to Mockito, I am trying to verify the attributes of an object which gets created inside a method.
pseudo code below:
class A{
...
public String methodToTest(){
Parameter params = new Parameter(); //param is basically like a hashmap
params.add("action", "submit");
return process(params);
}
...
public String process(Parameter params){
//do some work based on params
return "done";
}
}
I want to test 2 things:
when I called methodToTest, process() method is called
process() method is called with the correct params containing action "submit"
I was able to verify that process() is eventually called easily using Mockito.verify().
However trying to check that params contains action "submit" is very difficult so far.
I have tried the following but it doesn't work :(
BaseMatcher<Parameter> paramIsCorrect = new BaseMatcher<Parameter>(){
#Overrides
public boolean matches(Object param){
return ("submit".equals((Parameter)param.get("action")));
}
//#Overrides description but do nothing
}
A mockA = mock(A);
A realA = new A();
realA.methodToTest();
verify(mockA).process(argThat(paramIsCorrect))
Any suggestion ?
If you have got verify() to work, presumably it is just a case of using an argument matcher to check the contains of params.
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#3
The example given in the above docs is verify(mockedList).get(anyInt()). You can also say verify(mockedList).get(argThat(myCustomMatcher)).
As an aside, it sounds like you are mocking the class under test. I've found that this usually means I haven't thought clearly about either my class or my test or both. In your example, you should be able to test that methodToTest() returns the right result irrespective of whether or not it calls process() because it returns a String. The mockito folk have lots of good documentation about this sort thing, particularly the "monkey island" blog: http://monkeyisland.pl/.
Just pass Parameter in as a constructor argument to a constructor of the class A, then use a mocked instance/implementation of Parameter in your test and verify on the mock. That is how it is normally done - you separate your classes and compose them using constructor injection, that enables you to pass in mocks for testing purposes (it also allows rewiring the application and exchanging some commons a lot easier).
If you need to create Parameter on every function invocation you should use a factory that creates Parameter instances and pass that in. Then you can verify on the factory as well as the object created by the factory.

Categories