how to pass in multiple ArgumentMatchers to Mockito - java

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());

Related

Am I mocking the method call incorrectly or am I capturing the arguments on a mock interceptor incorrectly? [duplicate]

In Mockito documentation and javadocs it says
It is recommended to use ArgumentCaptor with verification but not with stubbing.
but I don't understand how ArgumentCaptor can be used for stubbing. Can someone explain the above statement and show how ArgumentCaptor can be used for stubbing or provide a link that shows how it can be done?
Assuming the following method to test:
public boolean doSomething(SomeClass arg);
Mockito documentation says that you should not use captor in this way:
when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);
assertThat(argumentCaptor.getValue(), equalTo(expected));
Because you can just use matcher during stubbing:
when(someObject.doSomething(eq(expected))).thenReturn(true);
But verification is a different story. If your test needs to ensure that this method was called with a specific argument, use ArgumentCaptor and this is the case for which it is designed:
ArgumentCaptor<SomeClass> argumentCaptor = ArgumentCaptor.forClass(SomeClass.class);
verify(someObject).doSomething(argumentCaptor.capture());
assertThat(argumentCaptor.getValue(), equalTo(expected));
Hypothetically, if search landed you on this question then you probably want this:
doReturn(someReturn).when(someObject).doSomething(argThat(argument -> argument.getName().equals("Bob")));
Why? Because like me you value time and you are not going to implement .equals just for the sake of the single test scenario.
And 99 % of tests fall apart with null returned from Mock and in a reasonable design you would avoid return null at all costs, use Optional or move to Kotlin. This implies that verify does not need to be used that often and ArgumentCaptors are just too tedious to write.
The line
when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);
would do the same as
when(someObject.doSomething(Matchers.any())).thenReturn(true);
So, using argumentCaptor.capture() when stubbing has no added value. Using Matchers.any() shows better what really happens and therefor is better for readability.
With argumentCaptor.capture(), you can't read what arguments are really matched.
And instead of using any(), you can use more specific matchers when you have more information (class of the expected argument), to improve your test.
And another problem:
If using argumentCaptor.capture() when stubbing it becomes unclear how many values you should expect to be captured after verification. We want to capture a value during verification, not during stubbing because at that point there is no value to capture yet. So what does the argument captors capture method capture during stubbing? It capture anything because there is nothing to be captured yet.
I consider it to be undefined behavior and I don't want to use undefined behavior.

How to check whether a method returns a null?

Assert.assertThat(refVar.method(), is(null));
Does the code is(null) correct to check whether the refVar.method() returns a null?
If not, how do i check whether something is a null or not?
I've tried aNull but the IDE says this method does not exist, i tried importing Matcher.* already.
Please help.
It looks like that jMock is not the right tool to do this. Mocks are usually used to have some kind of dummy implementation of some class/interfaces instead of having the actual production implementation of some class/interface in your unit tests. With jMock you write code like:
When method foo is called with the argument 42, the mock of that object/interface should return the string "abc".
However, jMock does not check if an existing class will return the value you expect. That is something "basic" JUnit tests will do. So you instance the class you want to check and call the methods you want to verify that it does indeed return the values it should return. So you write something like:
Assertions.assertNull(refVar.method());
This will verify that the return value of the refVar.method() call right there will return null. There is no need for jMock here.
Null or Not Null
The matchers aNull<T>(Class<T>) and aNonNull<T>(Class<T>) specify that an argument is null or is not null, respectively.
The following code specifies that the method "doSomething" must be called with two strings, the first must be null and the second must be not null.
oneOf (mock).doSomething(with(aNull(String.class)), aNonNull(String.class)));
Check this jMock Matchers for more clarifications

Mockito keeps returning Empty List

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).

How to mock multiple objects which will return non-null values

I need help in creating mocking two objects simultaneously.
If I set the return value of first mock obj i.e. mockClassA to null, it is working fine. I'm using annotations #Mock, #TestSubject of EasyMock. And if I don't set the first mock expectation's return as null, I'm seeing the following error.
java.lang.IllegalStateException: last method called on mock is not a void method
Here is the code, I'm trying:
EasyMock.expect(mockClassA.getValfromDB()).andReturn(ValA);
EasyMock.replay();
EasyMock.expect(mockoClassB.makeRestCall(EasyMock.anyString())).times(2).andReturn(httpResponse);
EasyMock.replay();
If EasyMock doesn't support mocking multiple objects in a single method, I'm allowed to use Mockito, PowerMockito, EasyMockSupport. Please feel free to suggest me something from those libraries too.
P.S: I already tried using replayall() from EasyMockSupport. But it didn't make any difference.
I could able to debug my code and found that I'm giving the no of times in wrong way.
Changing the line
EasyMock.expect(mockClassB.makeRestCall(EasyMock.anyString())).times(2).andReturn(httpResponse);
EasyMock.replay();
to
EasyMock.expect(mockClassB.makeRestCall(EasyMock.anyString())).andReturn(httpResponse);
EasyMock.expectLastCall().times(2);
EasyMock.replay();
has resolved my issue (Observe expectLastCall.times(2)).
Ref: TutorialsPoint.com
A mock must be passed to the replay() method. So your original code nor the answer are working. However, it is true that the times() must be after the andReturn().
So a correct code would be
expect(mockClassA.getValfromDB()).andReturn(ValA);
expect(mockClassB.makeRestCall(anyString())).andReturn(httpResponse).times(2);
replay(mockClassA, mockClassB);
or this with EasyMockSupport:
expect(mockClassA.getValfromDB()).andReturn(ValA);
expect(mockClassB.makeRestCall(anyString())).andReturn(httpResponse).times(2);
replayAll();
Note that I'm using static imports. It makes the code much more agreeable to the eyes.

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

Categories

Resources