Calling real method in Mockito, but intercepting the result - java

Simplifying a bit, our system has two parts. "Our" part, which in turn uses an lower level part implemented by another team (in the same codebase). We have a fairly complicated functional test setup, where we wrap the entry points to the lower level in spy objects. In positive tests we use the real implementation of that level, but we mock calls that should fail with some predefined error.
Now I am trying to add support for more complicated scenarios, where I would like to add an artificial delay for the calls made to the underlying level (on a fake clock obviously). To do this I would like to define a mock that would (1) Call the real implementation (2) Get the resulting Future object that is returned and combine it with a custom function that would inject the delay accordingly. So Ideally I would like to have something like:
doAnswer(invocationOnMock ->
{
result = call real method on mySpy;
return Futures.combile(result, myFunction);
}).when(mySpy).myMethod();
How can I achieve it?

As for me the easiest way it's just to save the link to the read object when you initialize your Spy object:
Foo realFoo = new Foo();
Foo spyFoo = Mockito.spy(realFoo);
Now you can stub it like this:
doAnswer(invocation -> realFoo.getSome() + "spyMethod").when(spyFoo).getSome();
One more way is to call invocation.callRealMethod():
doAnswer(invocation -> invocation.callRealMethod() + "spyMethod").when(spyFoo).getSome();
But in this case you may need to cast the return value as long as invocation.callRealMethod() returns Object.

Related

Mockito verify the last call on a mocked object

I have a bit of logic that needs to be tested such as:
{
...
A.add("1");
...
A.add("what ever");
...
A.add("2");
A.delete("5");
...
}
I have already mocked A in my test and I can test the add method is called once on argument ("2") such as:
Mockito.verify(mockedA).add("2");
My question is how can I test if I can verify the last call on method add is add("2") instead of other arguments.
Since the test above can't catch if somebody by accident adds another call such as add("3") in the last. Please notice that we don't care about other method invocations on A again afterwards. We also don't care about the times of the method called, the sequence of the methods called. The key point here is if we can verify the last true argument on a certain method of a certain mockedObject.
If you ask why do you need such functionality, I'd say in real world we might need to handle some logic that set something and the last set wins, and in order to avoid someone by accident set some other thing unexpected and I'd like to use our UT to catch this. And in order not to make the test too complex and neat, so I only expect to verify the last call on a certain method of a object instead verify something like order/noMoreInteractions/AtMostTimes and so on.
About the order of the invocations
By default, Mockito.verify() doesn't matter of the invocation order.
To take it into consideration, wrap the mock in an InOrder instance and perform the invocation verification on this instance.
About the no more interations
If the mock is no more invoked after the methods that you want to verify, you could use Mockito.verifyNoMoreInteractions(Object... mocks) that checks if any of given mocks has any unverified interaction such as :
InOrder inOrder = Mockito.inOrder(mockedA);
inOrder.verify(mockedA).add("1");
inOrder.verify(mockedA).add("2");
Mockito.verifyNoMoreInteractions(mockedA);
If the mock may still be invoked after the methods that you want to verify, you could add after your verifies an invocation to verify(T mock, VerificationMode mode) by passing a VerificationMode that checks that at most 2 invocations were performed.
InOrder inOrder = Mockito.inOrder(mockedA);
inOrder.verify(mockedA).add("1");
inOrder.verify(mockedA).add("2");
Mockito.verify(mockedA, Mockito.atMost(2)).add(Mockito.anyString());
A warning about your think and this way of mocking
Since the test above can't catch if somebody by accident adds another
call such as add("3") in the last.
Mockito provides a powerful and broad toolkit to work with mocks. Some features such as verify and more particularly verify that no more interaction was detected about a mock or a specific method of the mock make your test more complex to read and to maintain.
As well as, currently you want to check that the invocations on a mock were performed in a specific order. But you generally want to use these checks only as required that is according to the business/logic scenarios, not technical invocations.
For example supposing that in the tested method you have a case where for business reasons the mocked method is invoked 3 times and another case where the mocked method is invoked 2 times. It could make sense to check that it is only invoked 2 times and not more in the case with two expected invocations.
But in a general way, you should be cautious that your unit test doesn't overuse mocking verify that could look like as a assertion on the description of the flow and not a assertion on the behavior/logic.
Thanks #staszko032, inspired by the ArgumentCaptor, instead of getAllValues and verify the sequence, we can use getValue of captor since captor's getValue always get the last true argument. We can do it like this:
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
Mockito.verify(mockedA, Mockito.atLeastOnce()).add(captor.capture());
Assert.assertEquals("2", captor.getValue());
What this looks like to me is that you are mocking a data class. In my experience it's better to leave (stateful) data classes and mock (stateless) services. This way, you can verify that the method under test produces the correct data, rather than just verifying a series of invocations. Along with testdata builders (making it easy to instantiate your data classes with some default state, using builder pattern for instance), it becomes real easy to write tests.
If you do need to mock, the only way to test what you want is to use InOrder, and verify each of the invocations on the mock, and end with verifyNoMoreInteractions.
I've ended up implementing a new VerificationMode to do this. Here's the code in case it's useful to anyone.
class MostRecently implements VerificationMode {
#Override
public void verify(VerificationData data) {
MatchableInvocation target = data.getTarget();
List<Invocation> invocations = data.getAllInvocations();
if (invocations.isEmpty()) {
throw wantedButNotInvoked(target);
}
List<Invocation> targets = findInvocations(invocations, target);
if (targets.isEmpty()) {
throw wantedButNotInvoked(target);
}
Invocation lastInvocation = invocations.get(invocations.size() - 1);
if (target.matches(lastInvocation)) {
return;
}
ListIterator<Invocation> iterator = invocations.listIterator(invocations.size());
Invocation previous = iterator.previous();
Invocation undesired = previous;
while (!target.matches(previous)) {
undesired = previous;
previous = iterator.previous();
}
Invocation lastGoodInvocation = previous;
throw new MockitoAssertionError(join(
"Wanted most recent on '" + lastGoodInvocation.getMock() + "' to be " + lastGoodInvocation.getMethod(),
"No more interactions wanted after " + lastGoodInvocation.getLocation(),
"but found this interaction on mock '"
+ MockUtil.getMockName(undesired.getMock()) + "':",
undesired.getLocation(),
allLocations(invocations)));
}
static String allLocations(List<Invocation> invocations) {
StringBuilder sb = new StringBuilder("***\nFor your reference, here is the list of all invocations.\n");
int counter = 0;
for (Invocation i : invocations) {
sb.append(++counter).append(". ");
sb.append(i.getLocation()).append("\n");
}
return sb.toString();
}
}

Is it bad practice in Java to modify input object in void method?

In Java, assume you have a data object object with an attribute bar that you need to set with a value that is returned from a complex operation done in an external source. Assume you have a method sendRequestToExternalSource that send a request based on 'object' to the external source and gets an object back holding (among other things) the needed value.
Which one of these ways to set the value is the better practice?
void main(MyObject object) {
bar = sendRequestToExternalSource(object);
object.setBar(bar);
}
String sendRequestToExternalSource(MyObject object) {
// Send request to external source
Object response = postToExternalSource(object);
//Do some validation and logic based on response
...
//Return only the attribute we are interested in
return response.getBar();
}
or
void main(MyObject object) {
sendRequestToExternalSourceAndUpdateObject(object);
}
void sendRequestToExternalSourceAndUpdateObject(MyObject object) {
// Send request to external source
Object response = postToExternalSource(object);
//Do some validation and logic based on response
...
//Set the attribute on the input object
object.setBar(response.getBar());
}
I know they both work, but what is the best practice?
It depends on a specific scenario. Side-effects are not bad practice but there are also scenarios where a user simply won't expect them.
In any case your documentation of such a method should clearly state if you manipulate arguments. The user must be informed about that since it's his object that he passes to your method.
Note that there are various examples where side-effects intuitively are to be expected and that's also totally fine. For example Collections#sort (documentation):
List<Integer> list = ...
Collections.sort(list);
However if you write a method like intersection(Set, Set) then you would expect the result being a new Set, not for example the first one. But you can rephrase the name to intersect and use a structure like Set#intersect(Set). Then the user would expect a method with void as return type where the resulting Set is the Set the method was invoked on.
Another example would be Set#add. You would expect that the method inserts your element and not a copy of it. And that is also what it does. It would be confusing for people if it instead creates copies. They would need to call it differently then, like CloneSet or something like that.
In general I would tend to giving the advice to avoid manipulating arguments. Except if side-effects are to be expected by the user, as seen in the example. Otherwise the risk is too high that you confuse the user and thus create nasty bugs.
I would choose the first one if I have only these two choices. And the reason of that is "S" in SOLID principles, single responsibility. I think the job of doComplicatedStuff method is not setting new or enriched value of bar to MyObject instance.
Of course I don't know use case that you are trying to implement, but I suggest looking at decorator pattern to modify MyObject instance
I personally prefer the variant barService.doComplicatedStuff(object); because I avoid making copies

Mock object to run different void method

I am trying to write testcases for a method I've implemented that in turn uses a third party cache provider.
The problem I am facing is that the cache is asyncronous, making it quite hard to test since the element put into cache are not instantly in the cache.
My solution to this was to just mock the cache using PowerMockito.
I can make it so that it always returns the same object, but preferable I want it to put the object into a HashMapon put and get it from the same map on a get operation.
The get operation should be pretty simple, something like:
final Map<String, Object> cacheMap = new HashMap<>();
Answer<Object> getFunction = invocation ->
cacheMap.get(invocation.getArgument(0));
when(mockCache.get(any())).thenAnswer(getFunction);
But I am not sure how to mock a similar call for the void method mockCache.put(any(), any())
It atleast seems as if you cannot mock void functions to anything other than calling the real method or doing nothing.
I think you are looking for intercepting the original call and rerouting it to a different implementation. Have a look at this answer for an explanation how to do it.

Unit testing with mock that has mock inside

I need to unit test a certain method that works on an object of type X. The X object has few normal fields like String, int etc. but it also has a List of types Y. This Y type is also quite complex. And to make my problem even more difficult, let's say that the type Y has another list of type Z.
Ideally, I need to mock object X, but tell it to inject another mock of type Y inside, which should also inject another mock Z to itself (to Y). How should I do that?
And if I have so many few-levels mocks how should I avoid writing 20 specifications of what these mocks should actually return upon calling their methods?
Or is this a type of problem where I should use Builders and actually build a real object?
Thanks alot,
Bob.
Edit:
just an example usage code on top from my head:
public String produceImportantStringOfImportantData(ObjectX x) throws ParseException {
StringBuilder textResult = new StringBuilder();
List<ObjectY> listOfY = x.getListOfY();
if (listOfY.isValid()) {
for (ObjectY y : listOfY) {
for (ObjectZ z : y.getListOfZ()) {
textResult.append("<font color='green'>").append(z.getField2).append("</font>").append(": ").append(z.getSomething())
.append(" Label : ").append(z.getParentComponent.getField()))
.append(" some important labels: ").append(z.getField()))
.append(" some important labels ").append(y.getAnotherField))
.append(" different, important label: ").append(y.getField()))
.append("<br/>");
}
}
}
return textResult.toString();
}
Assuming you are using some mocking framework like Mockito, you could simply do:
X mockX = Mockito.mock(X.class);
Y mockX = Mockito.mock(Y.class);
Z mockX = Mockito.mock(Z.class);
Mockito.when(mockY.getZ()).thenReturn(mockZ);
Mockito.when(mockX.getY()).thenReturn(mockY);
If this gets too deep (you mention 20 specifications), it could be a sign that you are violating the Law of Demeter or the Single Responsibility Principle. In this case it means that your classes execute too much logic themselves rather than accepting some processors in their constructor which do the actual work.
If you would do this, you can test the processors separately and easily, and testing the entire process.
Please don't use mocks for this as there's absolutely no need to, but as you already seem to be aware, will lead to painful and fragile tests.
Or is this a type of problem where I should use Builders and actually build a real object?
You don't even need a Builder (although I do recommend them) - just use a real object. Using a real object will lead to a test that's must more resilient to refactoring, will test what your code is actually doing and not just what you think it is.

Unit tests for mapping methods that call getters and setters

Suppose I want to create a unit test for a method like this:
public Car map(CarReq request) {
Car car = new Car();
car.setPrice(carReq.getPrice());
car.setColour(carReq.getColour());
car.setType(carReq.getType());
// Other 20 lines like these
return car;
}
I can mock carRequest and tell each method what should return. But that's like not testing anything, as all the method does is getting values from carReq.
I can create a testing carReq object (without mocking) and check that the same values are copied into the output Car object. But that's a lot of work, right?
Isn't there a more intelligent way?
You want to test the logic of the method.
Therefore if what the method does is copying the properties of a CarReq into a Car, then this is what you should test:
#Test
public void mapTest() {
// Given
CarReq carReq = new CarReq(10000D, ...);
// When
Car car = myClass.map(carReq);
// Then
Assert.assertEquals(car.getPrice(), carReq.getPrice());
// ...
}
I'm not quite sure what the issue is ? Surely since the method takes a request and returns a new Car, that's precisely what you want to test ? If I was doing it, I would:
create a populated request and determine that the Car fields are what are in the request
perhaps assert that each invocation gives you a new Car ?
assert expected behaviour if you pass in a null (again, depending on the proposed usage of the method)
You say that all the method does is call setters/getters, but don't forget that one purpose of a unit test is to assert that the behaviour remains the same going forwards (i.e. you're testing for regressions). If you add additional functionality to this method, and you accidentally break something, the above test will tell you immediately.
Is it a lot of work ? Maybe (perhaps a few mins of copy/paste getter/setter invocations and changing params to be unique per attribute). But it's a lot less work than resolving an issue in production later on.
I can create a testing carReq object (without mocking) and check that
the same values are copied into the output Car object. But that's a
lot of work, right?
It is, but if you really are willing to unit-test this method, you have to do this.
Please note that you can use libraries like Orika to perform this kind of dumb field-mapping methods for you. Saves time and code lines :)

Categories