43

Is it possible to Mock a single method of a Java class?

For example:

class A {
    long method1();
    String method2();
    int method3();
}


// in some other class
class B {
    void someMethod(A a) {
       // how would I mock A.method1(...) such that a.method1() returns a value of my
       // choosing;
       // whilst leaving a.method2() and a.method3() untouched.
    }
}
auser
  • 6,307
  • 13
  • 41
  • 63

5 Answers5

86

Use Mockito's spy mechanism:

A a = new A();
A aSpy = Mockito.spy(a);
Mockito.when(aSpy.method1()).thenReturn(5l);

The use of a spy calls the default behavior of the wrapped object for any method that is not stubbed.

Mockito.spy()/@Spy

John B
  • 32,493
  • 6
  • 77
  • 98
8

Use the spy() method from Mockito, and mock your method like this:

import static org.mockito.Mockito.*;

...

A a = spy(new A());
when(a.method1()).thenReturn(10L);
npe
  • 15,395
  • 1
  • 56
  • 55
5

Based on Mockito's documentation the accepted answer is not the correct way to Spy real objects.

The right way to do this is to use the following pattern:
doReturn("foo").when(spy).get(0);

Below you can find the snippet from Mockito's about Spying on real objects.

Important gotcha on spying real objects!

Sometimes it's impossible or impractical to use when(Object) for stubbing spies. Therefore when using spies please consider doReturn|Answer|Throw() family of methods for stubbing. Example:

List list = new LinkedList();    
List spy = spy(list);

//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)   
when(spy.get(0)).thenReturn("foo");

//You have to use doReturn() for stubbing   
doReturn("foo").when(spy).get(0);   

Mockito does not delegate calls to the passed real instance, instead it actually creates a copy of it. So if you keep the real instance and interact with it, don't expect the spied to be aware of those interaction and their effect on real instance state. The corollary is that when an unstubbed method is called on the spy but not on the real instance, you won't see any effects on the real instance. Watch out for final methods. Mockito doesn't mock final methods so the bottom line is: when you spy on real objects + you try to stub a final method = trouble. Also you won't be able to verify those method as well.

magiccrafter
  • 5,175
  • 1
  • 56
  • 50
1

Assuming you are using jmockit:

public void testCase(@Mocked("methodToBeMocked") final ClassBoBeMocked mockedInstance) {
           new Expectations() {{
                   mockedInstance.methodToBeMocked(someParameter); returns(whateverYouLikeItToReturn);
           }}

   mockedInstance.callSomemethod();
}
Nathaniel Ford
  • 20,545
  • 20
  • 91
  • 102
Konstantin Pribluda
  • 12,329
  • 1
  • 30
  • 35
-3

You could simply create a subclass of A that overrides method1().

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • This wouldn't work - since you'd have to pass in an existing instance of A into the subclass of A in order for subclass to return a.method2() and a.method3() for calls to method2() and method3() respectively. Which means the subclass would have override method2() and method3(). – auser Jun 05 '12 at 11:01
  • @user63904: ah, so you want to modify the behaviour of method1 INSIDE someMethod() while still working with the instance of A that has been passed as a parameter? Right, that wouldn't work then. – Michael Borgwardt Jun 05 '12 at 12:09