Annotation Type Spy
-
@Retention(RUNTIME) @Target(FIELD) @Documented public @interface Spy
Allows shorthand wrapping of field instances in a spy object.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; private AutoCloseable closeable; @Before public void init() { closeable = MockitoAnnotations.openMocks(this); } @After public void release() throws Exception { closeable.close(); } ... }
Same as doing:
Foo spyOnFoo = Mockito.spy(new Foo("argument")); Bar spyOnBar = Mockito.spy(new Bar());
A 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) {} }
Important gotcha on spying real objects!
- Sometimes it's impossible or impractical to use
Mockito.when(Object)
for stubbing spies. Therefore for spies it is recommended to always usedoReturn
|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);
- 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 *un-stubbed* 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.
One last warning : if you call
MockitoAnnotations.openMocks(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 openMocks() in your JUnit runner (@RunWith) or use the built-inMockitoJUnitRunner
. Also, make sure to release any mocks after disposing your test class with a corresponding hook.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.
- Since:
- 1.8.3
- See Also:
Mockito.spy(Object)
,Mock
,InjectMocks
,MockitoAnnotations.openMocks(Object)
,MockitoJUnitRunner
- Sometimes it's impossible or impractical to use