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.
Related
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);
I read the tutorials but did not understand - how much of the mocked object should be implemented. Are we passing an interface or the entire implemented class to mock()?
What if you do not have the implementation? Do you need to create an interface - suppose you omit some methods out of ignorance of the actual implementation...
from example at mockito.org here
//mock creation
List mockedList = mock(List.class);
Do I need to create a class 'List' with the methods of the android List class?
Mockito's default implementation for every method is given by RETURNS_DEFAULTS, which (unless otherwise configured) defers to ReturnsEmptyValues:
Default answer of every Mockito mock.
Returns appropriate primitive for primitive-returning methods
Returns consistent values for primitive wrapper classes (e.g. int-returning method returns 0 and Integer-returning method returns 0,
too)
Returns empty collection for collection-returning methods (works for most commonly used collection types)
Returns description of mock for toString() method
Returns zero if references are equals otherwise non-zero for Comparable#compareTo(T other) method (see issue 184)
Returns an java.util.Optional#empty() empty Optional for Optional (see issue 191).
Returns null for everything else
For any mockable but unstubbed method on a class that you pass to Mockito.mock(), the mock method will have this behavior by default, regardless of whether you passed in a concrete class or an interface. In fact, Mockito encourages you to only stub the methods that are valuable to your system under test, and to let the defaults work for everything else. This is also the case if you "forget" to stub a method, or if new methods are added after you've written your test.
Note that for Mockito.spy, the default behavior is to delegate to (a copy of) the instance you pass to spy, and that by passing additional parameters to Mockito.mock you can change this "default answer" if you'd like.
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
my first question on StackOverflow. I'd like to be able to do something like:
SomeClass mock = mock(SomeClass.class);
String methodName = "someMethod"; OR Method method = ...someMethod...
Both of these things (the mock and the method) would combine to do the following:
when(mock.someMethod()).thenReturn(null);
Of course, the 'null' value will be changed accordingly for my needs, but I am trying to determine two things:
1) Is it even possible to do something like this in Java? This = combining a class object and a method into a methodCall.
2) How do I do such a thing?
I've researched this endlessly and I can't find anything. The problem is that even if this works with a regular class and a regular method (someClass and someMethod would come together to do someClass.someMethod()), keep in mind that this has to work with a mock object for use inside a when() call.
ANSWERED: when(method.invoke(mock)).thenReturn("Hello world."); is the correct syntax and reflection indeed does work inside a when() call. Thanks Kevin Welker!
Since you basically asked me to repost my comment, modified by your response, as an answer, here it is:
Try using reflection as in:
when(method.invoke(mock)).thenReturn("Hello world.");
although, I'm not sure how this is working for you, since you cannot mock/spy class Method (it is final). Mockito's when() only works on mocks or spies. If this is really working for you, can you post a little more detail?
If it doesn't work, you can -- as I suggested in my comment in the OP -- go the CGLib route and bypass Mockito. It's really not that difficult as it looks at first. In my OSS project Funcito (not a mocking framework), I stripped down a lot of the Mockito CGLib proxying code and rewrote it for my needs. It gives a much simpler view into the world of proxying classes, and intercepting method calls.
ADDITIONAL RESPONSE TO COMMENTS
I see how this is working for you, but I am not sure you really understand how it is working. The reason this might matter is because future changes to the way Mockito itself works could render your solution broken in the future. In essence, the reason it works is almost accidental, but yes it will work.
The way that when() is supposed to work is that what happens in between the parentheses is a method call on a previously created Mockito-generated mock or spy, which is just a fancy proxy of a class, rather than a real instance of the class. The proxies have special logic that intercepts the fake proxied method call and basically add that to a list of registered proxy-method invocations (it is stored in something called an IOngoingStubbing or something like that) for later use. Since Java evaluates parameters before invoking a method, this guarantees that the proxied method call gets registered/remembered before the when() method is actually executed. What the when() does is pops off this IOngoingStubbing, which then becomes the object on which thenReturns() is called.
You are not using this "correctly" but it still works for you. How? Well, all that needs to happen is that a method on the proxy needs to be called in order to be registered in a IOngoingStubbing before when() gets executed. You are not directly invoking a method on a proxy, but you are indirectly invoking a method on a proxy by passing the proxy to Method.invoke(). Hence the criteria is satisfied, and when() already has a proxy-method-call registered in an IOngoingStubbing.
You can see the same kind of "accidental" happiness in the following code, which appears at first to make no sense until you realize how Mockito works:
#Test
public void testSomething() throws Exception {
List listMock = mock(List.class);
Method m = List.class.getDeclaredMethod("get", int.class);
m.invoke(listMock, Mockito.anyInt());
when(null).thenReturn("Hello World"); // Huh? passing null?
assertEquals("Hello World", listMock.get(0)); // works!
}
The above test actually passes! Even though the argument to when is null, what counts is that the proxy (i.e., mock) instance had the correct method invoked on it prior to the when statement being invoked.
While it is unlikely that Mockito will change the basic way things work under the covers, there is still the potential for this to break for you sometime in the future. Like I said, it is more or less a happy accident that it works. As long as you understand the way it works and the risk involved, more power to you.
I think, adding a new method after class initialization is not possible as long as the method is not specified in the interface or class provided to Mockito. You would change the class signature after initialization and this is something which is not possible.
For stub method calls have a look to: http://code.google.com/p/mockito/. There is a sample on stub method calls.
If you want to get dynamic answers, not static ones, you should not use Mockito. Use a fake object or a stub to get you behavior for testing. See: http://martinfowler.com/articles/mocksArentStubs.html for details on this issue.
In Java, for each object, a new copy of instance variables is created which can be accessed using the object reference.
But in case of an instance method, only one copy of it(instance method) exists.
How is this method accessed by various object references?
The byte code (or native code if it's JIT'd) for the method is stored in one location. When the method is called, a pointer (under the hood, aka reference at a higher level) to the instance object is passed as the first argument so the method code can operate on that specific instance - have access to its fields, etc. In order to save space without additional performance cost, the calling mechanism in Java is quite a bit more complicated than C++, especially for interface methods.
Methods and fields are completely different. Methods apply to all instances of the object, but fields are per instance.
One way to think of it:
pretend the method is "global" to all instances, but it is "passed" an instance of the object via the "this" reference.
Methods can change the state of a particular instance, but they themselves are stateless.
Behind the scenes a reference to the object is passed to the method as part of the call. It may be useful to look at Java's reflection classes, Method.invoke() in particular.
From a previous answer of mine:
I'm sure the actual implementation is quite different, but let me explain my notion of method dispatch, which models observed behavior accurately.
Pretend that each class has a hash table that maps method signatures (name and parameter types) to an actual chunk of code to implement the method. When the virtual machine attempts to invoke a method on an instance, it gets the object's class, and looks up the requested signature in the class's table. If a method body is found, it is invoked, providing the original object as a reference called this.
Otherwise, the parent class of the class is obtained, and the lookup is repeated there. This proceeds until the method is found, or there are no more parent classes—which results in a NoSuchMethodError.
If a super class and a sub class both have an entry in their tables for the same method signature, the sub class's version is encountered first, and the super class's version is never used—this is an "override".
the implied reference "this" is passed in to each method, which of course you can reference explicitly
I'm assuming you're meaning on a simplistic level, as in how you actually do the call.
I'm also assuming you're refering to a method that has the static modifier in its signature, ie:
public static int getNum()
{
// code in here
return num;
}
If this is what you mean, and this was part of a class called 'SomeClass', then it would be accessed via the method call SomeClass.getNum(). ie, you put the actual class name before the method.
If this is not what you mean, ignore my answer :)