Mockito keeps returning Empty List - java

I'm working on unit testing a method in Mockito and mockito keeps sending an empty zero size list even when I have initialized the list that is to be returned.
This is the code to be tested. Note that nonCashIncludedPaymentPlanActive is always true ( Mocked ).
List<DebtAccountTransaction> debtAccountTransactionList = null;
boolean nonCashIncludedPaymentPlanActive = balancingPlanService.checkNonCashIncludedPaymentPlanParameter(debtAccountId);
if (nonCashIncludedPaymentPlanActive) {
debtAccountTransactionList = debtAccountTransactionDao
.getDebtAccountTransactionListByDebtAccountIdListWithCN(baseDebtIdAccountList, null);
}
if (debtAccountTransactionList.isEmpty()) {
throw new SfcException("DISPLAY.PAYMENT_PLAN_WITH_NO_BALANCE_SERVICE_FILE_CLOSED");
}
This the statement that keeps returning a List that I have mocked in mockito and added an item to it and here it returns an emptylist.
debtAccountTransactionList = debtAccountTransactionDao
.getDebtAccountTransactionListByDebtAccountIdListWithCN(baseDebtIdAccountList, null);
which then ofcourse gets caught by this line
if (debtAccountTransactionList.isEmpty()) {
throw new SfcException("DISPLAY.PAYMENT_PLAN_WITH_NO_BALANCE_SERVICE_FILE_CLOSED");
}
Thus inorder to avoid this path of execution I have done the following in Mockito:
when(debtAccountTransactionDao.getDebtAccountTransactionListByDebtAccountIdListWithCN(baseDebtIdAccountList, null)).thenReturn(
debtAccountTransactionList);
and declaration of debtAccountTransactionList is :
DebtAccountTransaction debtAccountTransaction = spy(DebtAccountTransaction.class);
debtAccountTransaction.setId(2L);
List<DebtAccountTransaction> debtAccountTransactionList = new ArrayList<DebtAccountTransaction>();
debtAccountTransactionList.add(debtAccountTransaction);
I tried mocking a List, tried different argument captors but nothing seems to work. When I debug it, Mockito does fill up the debtAccountTransactionList but with an empty List, thus it fails.
Any help with how I can make sure that Mockito sends a Non-Empty Non-Zero List so that it can bypass the isEmpty() check.

A good rule of thumb in writing tests, especially with a mocking library like Mockito: Don't confuse stubbing with verification. Stubbing (when) is about getting your system under test (SUT) into the desired state, not about asserting anything about how the SUT behaves.
In Mockito, the way to make assertions about how the SUT behaves is after the SUT runs, using verify calls. If you don't have any verify calls, you're not actually asserting anything, and your SUT can misbehave without your test catching it, which is obviously a bad thing.
As a result, it's usually best to make your matchers for stubbing (when) as broad as possible, since the goal of stubbing is just to make sure you fall into the right test case. For example, you can and often should use matchers like any() in your when() call. If you did that, you would sidestep the issue you're having here.
If you want to make assertions about the values that the SUT actually used as arguments, do that with verify, or possibly by capturing the value and making additional assertions about it directly.

The problem is the mock creation/behavior registration. This doesn't match what you put into the method and hence returns to the default behavior of returning an empty list.
as pointed out by M. Deinum
Thus there was a problem in acceptance of the argument by Mockito and it would ignore my stubbing and then return an empty list by default.
I fixed it by making sure the object that is baseDebtIdAccountList passed to the function when(debtAccountTransactionDao.getDebtAccountTransactionListByDebtAccountIdListWithCN(baseDebtIdAccountList, null)).thenReturn(
debtAccountTransactionList) is exactly the same in the rest of the code. Thus there was a mismatch in the arguments and Mockito used the default way of using an empty list.

Did you put in any place of the code something like:
debtAccountTransactionDao = Mockito.mock(NameOfTheClassOfThisDebtAccountObject.class);
?
You should put something like this before calling the method getDebtAccountTransactionListByDebtAccountIdListWithCN, so it knows it should use the mocked behavior, not the normal behavior of the method (that could be return an empty list).

Related

good practice for testing mocked object

It is good practise to match mock objects widely but verify them precisely.
for example:
Using this:
when(myMock.has(any())).thenReturn(myValue);
Rather than:
when(myMock.has(eq("blah")).thenReturn(myValue);
Along with:
var result = myMethod();
assertThat(result, is(myValue));
Because it is making sure that it is always returned myValue regardless of the has method input.
There was a good explanation for this rule but I can not find it.
something along the lines: match widely and verify precisely.
It would be great if you can advise me about the name of the rule or some reference to it?
The explanation is quite simple: It will make your live easier.
Imagine the case that a caller will not call your method with "blah". In this case you rely on the mocking framework what will be returned, most likely null, zero or false. Your test will then run into a different direction or even fail with a NullpointerException. For other developers it will be hard to understand what went wrong here.
If you match widely, your test will continue as expected, but you should place a verification afterwards that makes the test fail with a clean reason. Developers tend to omit the verification step, wich renders the test useless quite often.
Usually there is no reason to match on a precise parameter value, except for the case when you want your mock to act differently on two values.
Most frameworks provide methods for the method call verification, e.g. Mockito:
#Mock
private Repository repository;
#Test
private void testReadData() {
Mockito.when(repository.findById(any())).thenReturn(yourEntity);
// run your test
Mockito.verify(repository).findById("foo");
}

Mockito Invalid use of matchers Mock(Object.class) & anyString()

Ola,
I'm busy writing a unit test like
monitor.severe(mock(MonitorEventType.class), anyString());
When I execute this I get:
Invalid use of argument matchers.
0 matchers expected, 1 recorded.
So I tried:
monitor.severe(mock(MonitorEventType.class), eq(anyString()));
But this gave
Invalid use of argument matchers.
0 matchers expected, 2 recorded.
I also tried to use
monitor.severe(any(MonitorEventType.class), anyString());
but this gives a null pointer.
What works is
monitor.severe(mock(MonitorEventType.class), "");
But thats not what I want.
My testMethod is :
#Test
public void testSevere() {
monitor.severe(mock(MonitorEventType.class), eq(anyString()));
ArgumentCaptor<DefaultMonitoringEventImpl> captor = ArgumentCaptor.forClass(DefaultMonitoringEventImpl.class);
verify(event).fire(captor.capture());
DefaultMonitoringEventImpl input = captor.getValue();
assertThat(fetchMonitorLevel(input), equalTo(MonitorEventLevel.SEVERE.getDescription()));
}
private String fetchMonitorLevel(DefaultMonitoringEventImpl input) {
Map<String, String> map = input.getMonitorEventWaardes().getWaardenLijst();
return map.get(MonitorEvent.MONITOR_EVENT_LEVEL_KEY);
}
And the method under test is:
public void severe(MonitorEventType type, String message) {
write(type, MonitorEventLevel.SEVERE, message, null);
}
#Asynchronous
public void write(MonitorEventType type, MonitorEventLevel level, String message, MonitorEventWaardes pEventWaardes) {
event.fire(new DefaultMonitoringEventImpl(type, level, message, pEventWaardes));
}
What I want is that When I call monitor.severe with a random MonitorEventType and a random String that the "level" parameter in teh event.fire call is filled with the right value.
First, some basics:
A mock is a replacement for a real object, that you can create using a mock framework. It records its interactions and verifies them for later.
A matcher like any, anyString, or eq tells your mock framework (not your test framework or your system under test) what kind of calls are relevant for stubbing (telling your mock how to behave when its method is called) or verifying (asking your mock framework whether or not a certain method was called).
Most importantly, JUnit and Mockito do not allow for statements like "test this for any input": Statements like any only exist so you can say "when I receive any parameter, take this action" or "check that a method was called with any parameter".
So now your examples:
/* BAD */ monitor.severe(mock(MonitorEventType.class), anyString());
This doesn't work because monitor is real, so anyString is out of place. Your mock is fine there, though, because you're supplying a mock implementation to test a real implementation.
/* BAD */ monitor.severe(mock(MonitorEventType.class), eq(anyString()));
This is the same problem as above, but doubly so: eq should take a real value, never a matcher like anyString.
/* BAD */ monitor.severe(any(MonitorEventType.class), anyString());
Here you've supplied two matchers into a real method call. The matchers are just a signal to Mockito, and a real implementation is processing this, not Mockito.
/* OK */ monitor.severe(mock(MonitorEventType.class), "");
You're supplying a mocked implementation and a real string to your real system-under-test, so this is a proper use of Mockito, even if it doesn't express what you want to test.
Besides the use of Mockito, the real issue here is that you want to introduce randomness into your test. Even if Mockito were the right tool for the job—it definitely isn't—then your test might pass 90% of the time and fail 10% of the time depending on which input is picked. This will make your tests noisy/flaky at best, and may even lead your team to dismiss the value of testing in general.
Instead, pick representative use cases or edge cases; if you have an enum-type parameter, you can also iterate across all values and run the test once per value. You probably don't need Mockito for this, unless you can't easily create a MonitorEventType instance for some reason; then you might use Mockito to create a fake MonitorEventType for interacting with your real Monitor under test.

How does a Mockito spy know when it is spying?

This code from the documentation is totally baffling me:
List list = new LinkedList();
List spy = spy(list);
when(spy.size()).thenReturn(100); // <--- how does this spy know
// not to call the real method????
//using the spy calls *real* methods
spy.add("one");
spy.add("two");
I get it, Mockito is weird and hardly still in Java. Confusing thing is spy.* has to evaluate fully before it knows whether it's wrapped in a when() or something. How on earth would the first spy.* method not call on the real object but the later ones doe?
According to the documentation the first when(spy.size()).thenReturn(100) will actually invoke the real List.size() method, see: http://mockito.github.io/mockito/docs/current/org/mockito/Mockito.html#13
Each subsequent call of course will then return the mocked result.
If you don't want the real method to be called (e.g. when(spy.get(0)).thenReturn(...) would probably throw an IndexOutOfBoundsException, you have to use this pattern: doReturn(...).when(spy).get(0);
I don't know the exact implementation, but I can take a guess.
The call to spy(...) first proxies the given object and keeps it as a reference to delegate calls.
The call
when(spy.size()).thenReturn(100);
is practically equivalent to
Integer result = spy.size();
OngoingStubbing<Integer> stubbing = when(result); // result is useless
stubbing.thenReturn(100);
The first call to size() is invoked on the proxy. Internally, it can register the call, pushing it, for example, on a static (global) Mockito stack. When you then invoke when(), Mockito pops from the stack, recognizes the call to size() as needing stubbing and performs whatever logic required to do so.
This can explain why stubbing in a multithreaded environment is bad business.

Mockito vs JMock

I am experimenting with converting some of my unit tests from using JMock to using Mockito and have hit a few stumbling blocks.
Firstly in my tests when using JMock the verification and returning of the stub happen in one step as follows
contextMockery.checking(new Expectations() {{
oneOf(dateUtilityService).isBeforeToday(URGENT_DATE);
will(returnValue(true));
}});
This essentially verifies that the method is being called and returns a canned value at the same time. The test fails if isBeforeToday method is NOT called and returns my canned value of true at the same time. Whereas when using Mockito I have to verify that the method is being called and then return my canned value in separate steps which are pretty much a duplicate as follows:
doReturn(true).when(dateUtilityService).isBeforeToday(URGENT_DATE);
verify(dateUtilityService).isBeforeToday(URGENT_DATE);
Is there no way to do this in one step?
Secondly, if I forget to list a method call to one of my mocks in my expectations, JMock fails the test with "Unexpected invocation exception" which in my opinion is correct whereas Mockito will happily pass the test unless I explicitly verify that a method call to the mock must never happen, is this correct (seems wrong)? Is there a way to tell mockito to fail the test if unexpected method calls are made to my mocked out dependencies?
1.
When you stub a method call the verify method is usually not necessary - you should check the action based on the return value (in your case something might happen or something will be returned when the dateUtilityService returns true - check that instead of verifying interaction with a mock.
Mockito documentation also talks about this. http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html#2
2.
This actually leads to fragile tests and is not recommended way of doing things with mockito. That's why there is no way to set this behaviour.
See http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html#8

how to pass in multiple ArgumentMatchers to Mockito

I have two custom ArgumentMatchers and I'd like my mock to return a different value based on the argument value.
Example:
when(myMock.method(new ArgMatcher1()).thenReturn(false);
when(myMock.method(new ArgMatcher2()).thenReturn(true);
Unfortunately, the second call to when() results in an exception. This makes sense to me because, if the argument matches both ArgumentMatchers, Mockito wouldn't know whether to return true or false. Is there a way to do this in Mockito? It could even be something like:
when(myMock.method(new ArgMatcher2()).thenReturn(false).elseReturn(true);
I'm not sure how your matchers are coded, but having two different matchers is supported of course, maybe the method you are stubbing is not mockable via Mockito (final).
Also for the record it is possible to tell the stub to return different return values in different ways :
when(myMock.method(new ArgMatcher2()).thenReturn(false, false, true).thenReturn(true);
If you're interested in returning a default value from Mockito, then this I have achieved like that:
when(myMock.myMethod(any())).thenReturn(true);
when(myMosk.myMethod("some other argumetn")).thenReturn(true);
Will it help you? Hard to say, I haven't used matchers the way you do with new keyword. It might be, that Mockito doesn't understand that well your custom matchers.
Switch to syntax:
doAnswer(args->false).when(myMock).myMethod(any());

Categories

Resources