Does when() in Mockito verify invocation with strict parameter? - java

I am curious if when(mock.method(SPECIFIC_PARAM)).thenReturn(RETURN_VAlUE); checks for invocation of method. Or should I do verify(mock).method(SPECIFIC_PARAM); to make sure the method has been invoked?

If you use #RunWith(MockitoJUnitRunner.class) or #ExtendWith(MockitoExtension.class), you will get an UnnecessaryStubbingException after running a test if you provided a mock that is not used.
You can avoid this by setting #MockitoSettings(strictness = Strictness.LENIENT) if you want to.
But even with the UnnecessaryStubbingException, it's still better to do an actual verify inside your test for readability. Your 'verify' can also be stricter than your stub, e.g:
when(mock.method(anyCollection())).thenReturn(...)
...
mock.method(collection);
...
verify(mock).method(argThat(collection -> collection.size()==1));

Basically when(mock.method(SPECIFIC_PARAM)).thenReturn(RETURN_VAlUE); signifies that when the method is invoked on the mock then the specified value is returned. The whenis used to configure the mocking, so it doesn't perform any verifications. It is the verify that checks if a method is called.

With the method when(..).thenReturn(...) you are defining a rule on the mock object, in your particular case, you are instructing the mock object to return "RETURN_VALUE" when the method mock.method is invoked with input parameter "SPECIFIC_PARAM".
You are actually not asserting anything over the mock object.
Instead, you can check the effective invocation of the mock's method, by using verify(mock), as you did in your description.
For example, this is what you should expect when your method is not invoked:
got: <Wanted but not invoked: mock.method(SPECIFIC_PARAM);

Related

Unwanted mock with mockito

I'm doing unit tests with jUnit 5 and Mockito. In one test, I had to mock a method. Everything works fine. In another test later I'm invoking the same method but this time I don't want Mockito to do anything. Nevertheless, Mockito returns an unasked null value, which makes my test fail.
I thought it was due to the first test, so I added Mockito.reset(). But it didn't change anything.
Do you understand what's happening behind the scene?
I ran the debug mode to have more info about the object created by Mockito. Among other infos I can read
invocationForStubbing: ecritureComptable.toString();
But I don't know where and when this method is called.
Any help appreciated.
EDIT....
Thank you guys. I edited my post to make it clearer and also because I have now a better idea of what possibly happened:
1/ Before each test, I create a mock of the object DaoProxy and I use the mode RETURNS_DEEP_STUBS, which have mockito mock objects nested in DaoProxy
#BeforeAll
private static void injectMockDao() {
DaoProxy daoProxyMock = mock(DaoProxy.class, Mockito.RETURNS_DEEP_STUBS);
AbstractBusinessManager.configure(null, daoProxyMock, null);
}
2/ For a specific test method, I use :
when(getDaoProxy().getComptabiliteDao().getEcritureComptableByRef(Mockito.anyString())).thenReturn(ecritureBDD);
and reset it after use, hopping that by the next call of the all chain, Mockito won't do anything (but it didn't work) :
reset(getDaoProxy().getComptabiliteDao().getEcritureComptableByRef(Mockito.anyString()));
3/ In another test later, i make a call to
getDaoProxy().getComptabiliteDao().getEcritureComptableByRef()
and Mockito - although unasked - returns a null object.
The input of #Gavin makes me assume this is because of the RETURNS_DEEP_STUBS-Mocking of DaoProxy. Mockito mocks the nested object, but since it has no info on what it should return, it returns the default object value : null. This explains why in this case the reset didn't help.
If your object is marked for mocking with #Mock or you have used the mock method to create it then Mockito will return the default value for the type, which for objects is null.
In the failing test you could try to either provide a mocked value in the usual way, or inject a "real" instance of the object being mocked, I believe it is possible to have Mockito to provide a mocked response on a "real" instance of an object.
If you want to make real method call in the second test then use thenCallRealMethod() in the second test
when(mock.someMethod()).thenCallRealMethod();

How to verify that were not invocation of methods of the mock object? Mockito

How to verify that there were no invocations of methods of the mock object?
I want something like that:
Mockito.assertNoOneMethodWasCalled(myMockObject);
If you want to check that no interaction happened at all:
verifyZeroInteractions(Object... mocks)
If you want to check that no interactions happened after certain calls:
verifyNoMoreInteractions(Object... mocks)
If you want to verify single method:
verify(mock, never()).methodCall();
verify(mock, times(0)).methodCall();

EasyMock void method

I'm trying to use EasyMock to mock out some database interface so I can test the business logic off a wrapping method. I've been going ok with methods that return by using the following in my setup of my test.
DBMapper dbmapper = EasyMock.createMock(DBMapper.class);
userService.setDBMapper(dbmapper);
then within my actual test I run
EasyMock.expect(dbmapper.getUser(userId1)).andReturn(mockUser1);
EasyMock.replay(dbmapper);
userService.getUser(userId1);
This service then connects to the dbmapper and returns the object (the mapper is injected using setter methods)
These type of mocks seem to work fine. However when I try to run a test for
userService.addUser(newUser1);
This method calls a void method.
dbmapper.createUser(newUser);
It's this method that I'm having problems mocking out.
I've tried the following
EasyMock.expectLastCall();
EasyMock.replay(dbMapper);
userService.addUser(newUser1);
as some other posts/questions etc seem to suggest I get an IlligalStateException: no last call on a mock available
Can anyone point me in the right direction please?
Many Thanks in advance
You're close.
You just need to call the method on your mock before calling expectLastCall()
So you expectation would look like this:
userService.addUser(newUser1);
EasyMock.expectLastCall();
EasyMock.replay(dbMapper);
userService.addUser(newUser1);
This works because the mock object is in Record mode before the call to replay(), so any calls to it will perform default behaviour (return null/do nothing) and will be eligible for replaying when the replay() method is called.
What I like to do to make sure that it is obvious the method call is for an expectation is to put a small comment in front of it like this:
/* expect */ userService.addUser(newUser1);
EasyMock.expectLastCall();
EasyMock.replay(dbMapper);
userService.addUser(newUser1);
This problem does not happens if you use the 'nice' API:
DBMapper dbmapper = EasyMock.createNiceMock(DBMapper.class);
There are two kinds of mock - strict and nice. The strict mock throws Assertion Error in case an unexpected method is called. The nice mock allows unexpected method calls on the mock.
For further details, refer to the official doc - http://easymock.org/user-guide.html#mocking-strict

How does when() work?

In the following example
when(myMethod("abc", 123)).thenReturn(456);
How does the when() method catch the method name and arguments without actually invoking myMethod()?
Can I write a method to do the same thing as when() so that I get a method pointer and an array of Objects as arguments to invoke later?
The method myMethod is invoked. But it is being invoked on a mock object -- that's the "trick".
Of course you can write code that accepts a "method pointer" (in Java, it would be an object of class Method) and some arguments, and use invoke, but doing so does not actually buy you anything over calling the mock object's myMethod directly.
It is more common to see when called as follows:
MyObject myObject = mock(MyObject.class);
when(myObject.myMethod("abc", 123)).thenReturn(456);
Try printing (or logging) the expression
myObject.getClass().getName()
here. You will see that the class of the mock object is not actually MyObject. But it is of a class that has the same interface. The calls on this object update some internal state. This allows Mockito to keep track of how it is used, and allows you to assert various things.
In your above example, myMethod is a method on a mock object. Without any expectations, Mockito will return null, 0, or false depending on the data type, which when will silently discard.
However, You may also use when on an object which is not a mock, but rather an object created using Mockito.spy(). In this case, the method would actually be called in the when method, which is often not what you want to do. Mockito provides another method called doReturn (or possibly doAnswer or doThrow) which provides you a replacement object so the original is never called (docs):
doReturn(1).when(mySpiedObject).getSomeInteger(anyString(), eq("seven"));
Note that the Mockito docs recommend using when rather than doReturn because the latter is not type-safe.

How to ignore unexpected method calls in JUnit/easymock?

I'm just wondering if it is possible using Junit and easymock to ignore unexpected method calls?
I.e. instead of the test failing I want to be able to say - "at this point - ignore any unexpected method calls and just continue with the test as normal'
Thanks
With EasyMock you can create a nice mock, which unlike a normal mock object does not throw assertion errors if an unexpected/recorded call occurs. To quote the easymock documentation...
On a Mock Object returned by createMock() the default behavior for all methods is to throw an AssertionError for all unexpected method calls. If you would like a "nice" Mock Object that by default allows all method calls and returns appropriate empty values (0, null or false), use createNiceMock() instead.
To create a nice mock, use the static createNiceMock(Class class) method on the Easymock class...
SomeClass someClassNiceMock = EasyMock.createNiceMock(SomeClass.class);
Reference: http://easymock.org/user-guide.html#mocking-nice

Categories

Resources