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.
Related
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).
Java 8, TestNg 6.8.1, Mockito 1.10.19.
This is my first experience with Mockito. I stub two methods in a class, both of them take a String and a double as parameters and return double. I only care about the second parameter in this case.
When the stubbed methods are called during the execution of my unit test stubbing works fine only once. The subsequent calls to the stubbed methods return 0 instead of increasing/decreasing the parameter. I interpret this as if the methods are not longer stubbed.
Here is the code
MyManager myManagerMock = mock(MyManager.class);
when(myManagerMock.method1(someString, someDouble)).thenReturn(someDouble + 0.5d);
when(myManagerMock.method2(someString, someDouble)).thenReturn(someDouble - 0.5d);
// the class ClassBeingTested has a private member of the type MyManager
ClassBeingTested classBeingTested = new ClassBeingTested(myManager);
// the method getSomeDoubleValue() will perform several calls myManagerMock.method1 and myManagerMock.method2
assertThat(classBeingTested.getSomeDoubleValue(someString, someDouble), is(anExpectedDoubleValue));
Here is how method 1 and method2 are called inside ClassBeingTested:
method2(someString, method1(someString, someDouble));
I wonder what I am doing wrong. As far as I understand stubbed methods can be called repeatedly and they are supposed to repeatedly return the value supplied in the "thenReturn()" method.
Thanks in advance to all who can help..
The key necessary to solve the puzzle (I missed this in the original version of the question, which I have now edited following a suggestion of a fellow forum member) was the way I called the stubbed methods inside classBeingTested.getSomeDoubleValue(someString, someDouble). This is how the calls in question look like method2(someString, method1(someString, someDouble)); . You probably can see my mistake right away.
method1 received the value someDouble, while method2 received someDouble - 0.5d returned by the method1. This is the reason why Mockito did not recognize the stubbing of method2 and the method returned 0.0d.
I had to rewrite my original "mocking"
when(myManagerMock.method1(someString, someDouble)).thenReturn(someDouble + 0.5d);
when(myManagerMock.method2(someString, someDouble)).thenReturn(someDouble - 0.5d);
and make it look this way so that the actual parameter values do not matter anymore
when(myManagerMock.method1(anyString(), anyDouble())).thenReturn(11.5d);
when(myManagerMock.method2(anyString(), anyDouble())).thenReturn(10.5d);
After that everything worked fine. I also had to abandon my "smart" processing in the "thenReturn" method.
You will have to modify the thenReturn part to return multiple values. Something like -
.thenReturn(someDouble + 0.5d, someDouble + 0.5d,..);
Mokito expects us to provide the return values as many times the stubbed method is called during test case execution. Try this and it should work fine.
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
I am attempting to set up a when statement for a method used inside another method I am testing. Inside the method I am testing I am creating a list which I have no reference to, therefore I cannot mock it. I would like to validate the contents of this list when it is used in the above mentioned method inside. I have used the following as part of the when method, but ended up with an "InvalidUseOfMatchersException" in every case. What am I missing?
Matchers.eq(mockKeys) //mockKeys is a List<String> with expected contents
Matchers.anyListOf(String.class)
Mockito.when(myDaoImpl.getRecords([either of the above])).thenReturn(mockResult);
I must refuse to provide exact code.
List<String> mockKeys = createMockKeys(); // defined elsewhere
when(myDaoImpl.getRecords(Matchers.eq(mockKeys))).thenReturn(mockResult);
when(myDaoImpl.getRecords(mockKeys)).thenReturn(mockResult); // implicitly equal
when(myDaoImpl.getRecords(Matchers.anyListOf(String.class)))
.thenReturn(mockResult);
All of the above are fine. Nothing you've posted looks inherently wrong; it's more likely a problem we can't see, such as if getRecords is final, or in a use of Mockito or Matchers surrounding your code. Though it is understandable not to be able to post more code than you can, it may make it hard to provide a more-specific answer.
For the sake of debugging, place a call to Mockito.validateMockitoUsage() before and after your stub. This will help ensure that the problem is actually on the line you think it is, and not pollution from calls before or after.
Your problem is the two lines Matchers.eq(mockKeys); and Matchers.anyListOf(String.class). As the message says, you're using them invalidly.
Mockito uses its own data structure to store a matcher when you call such a method, but returns a different value from the actual call. That additional value must be passed to the method that you're stubbing (getRecords in this case), and when you stub, Mockito retrieves the actual matchers from the data structure.
Unless you completely understand how the data structure works, and know exactly what you're doing, you really need to put the calls to the two Matchers methods inside the call to getRecords. For example,
when(myDaoImpl.getRecords(eq(mockKeys), anyListOf(String.class))).thenReturn(mockResult);
In mockito, is it possible to capture the previous value set to a field of an object passed to a mock object's method for example the method under test performs this
public void methodUnderTest(){
Person person = new Person();
person.setAge(5);
someObject.setPerson(person);
...
person.setAge(6);
someObject.setPerson(person);
}
What I wanted to know is if I mock someObject, will I be able to verify that someObject performed setPerson to a single object "person" twice but the object had different value for age when setPerson occurred? I tried using ArgumentCaptor but since I passed the same object, I was just able to get the last age.
ArgumentCaptor<Integer> arg = ArgumentCaptor.forClass(Integer.class);
verify(mockObject).setPerson(arg.capture());
List<Integer> captureList = arg.getAllValues();
captureList.get(0).getAge(); // returns 6
captureList.get(1).getAge(); // returns 6
I also tried doing
InOrder in = inOrder(mockObject);
in.verify(mockObject).setPerson(arg.capture());
assertEquals(5, arg.getValue().getAge()); //fails
Unfortunately, you can't do that with an ArgumentCaptor.
The captor only stores a reference to the argument; in this case, it stores twice a reference to the same object, person.
You should try using an Answer, to perform the proper check every time the setPerson method is called.
This mockito issue is related to what you're trying to do.
Can't you just do
verify(mockedList, times(1)).setPerson(eq(5));
verify(mockedList, times(2)).setPerson(eq(6));
Been a while since I used mockito so I think that's the right syntax.
Or do you need to capture the value for some other reason than assertions?
I think it is not possible with Mockito. You may rewrite your code to make it "unit testatble" or much better by writing the test first and the code after in a TDD approach.
However if for some reasons you can't modify your code, it is possible to use PowerMock features. For example PowerMockito.whenNew will allow you to provide a mock of A. But this approach is not recommended.