@Retention(value=RUNTIME)
@Target(value=FIELD)
@Documented
public @interface Spy
Example:
public class Test{
//Instance for spying is created by calling constructor explicitly:
@Spy Foo spyOnFoo = new Foo("argument");
//Instance for spying is created by mockito via reflection (only default constructors supported):
@Spy Bar spyOnBar;
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
...
}
Same as doing:
Foo spyOnFoo = Mockito.spy(new Foo("argument"));
Bar spyOnFoo = Mockito.spy(new Bar());
The field annotated with @Spy can be initialized by Mockito if a zero argument constructor can be found in the type (even private). But Mockito cannot instantiate inner classes, local classes, abstract classes and interfaces. The field annotated with @Spy can be initialized explicitly at declaration point. Alternatively, if you don't provide the instance Mockito will try to find zero argument constructor (even private) and create an instance for you. But Mockito cannot instantiate inner classes, local classes, abstract classes and interfaces. For example this class can be instantiated by Mockito :
public class Bar {
private Bar() {}
public Bar(String publicConstructorWithOneArg) {}
}
Mockito.when(Object)
for stubbing spies.
Therefore for spies it is recommended to always use doReturn
|Answer
|Throw()
|CallRealMethod
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);
One last warning : if you call MockitoAnnotations.initMocks(this)
in a
super class constructor then this will not work. It is because fields
in subclass are only instantiated after super class constructor has returned.
It's better to use @Before.
Instead you can also put initMocks() in your JUnit runner (@RunWith) or use the built-in
MockitoJUnitRunner
.
Note that the spy won't have any annotations of the spied type, because CGLIB won't rewrite them. It may troublesome for code that rely on the spy to have these annotations.
Mockito.spy(Object)
,
Mock
,
InjectMocks
,
MockitoAnnotations.initMocks(Object)
,
MockitoJUnitRunner