• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 package org.mockitousage.annotation;
6 
7 import java.util.AbstractList;
8 import java.util.ArrayList;
9 import java.util.Arrays;
10 import java.util.LinkedList;
11 import java.util.List;
12 import org.junit.Rule;
13 import org.junit.Test;
14 import org.junit.rules.ExpectedException;
15 import org.mockito.Mock;
16 import org.mockito.MockitoAnnotations;
17 import org.mockito.Spy;
18 import org.mockito.exceptions.base.MockitoException;
19 import org.mockitoutil.TestBase;
20 
21 import static junit.framework.TestCase.assertEquals;
22 import static junit.framework.TestCase.assertNotNull;
23 import static junit.framework.TestCase.assertTrue;
24 import static junit.framework.TestCase.fail;
25 import static org.assertj.core.api.Assertions.assertThat;
26 import static org.mockito.Mockito.doReturn;
27 import static org.mockito.Mockito.never;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.Mockito.when;
30 
31 @SuppressWarnings("unused")
32 public class SpyAnnotationTest extends TestBase {
33 
34     @Spy
35     final List<String> spiedList = new ArrayList<String>();
36 
37     @Spy
38     InnerStaticClassWithNoArgConstructor staticTypeWithNoArgConstructor;
39 
40     @Spy
41     InnerStaticClassWithoutDefinedConstructor staticTypeWithoutDefinedConstructor;
42 
43     @Rule
44     public final ExpectedException shouldThrow = ExpectedException.none();
45 
46     @Test
should_init_spy_by_instance()47     public void should_init_spy_by_instance() throws Exception {
48         doReturn("foo").when(spiedList).get(10);
49         assertEquals("foo", spiedList.get(10));
50         assertTrue(spiedList.isEmpty());
51     }
52 
53     @Test
should_init_spy_and_automatically_create_instance()54     public void should_init_spy_and_automatically_create_instance() throws Exception {
55         when(staticTypeWithNoArgConstructor.toString()).thenReturn("x");
56         when(staticTypeWithoutDefinedConstructor.toString()).thenReturn("y");
57         assertEquals("x", staticTypeWithNoArgConstructor.toString());
58         assertEquals("y", staticTypeWithoutDefinedConstructor.toString());
59     }
60 
61     @Test
should_allow_spying_on_interfaces()62     public void should_allow_spying_on_interfaces() throws Exception {
63         class WithSpy {
64             @Spy
65             List<String> list;
66         }
67 
68         WithSpy withSpy = new WithSpy();
69         MockitoAnnotations.initMocks(withSpy);
70         when(withSpy.list.size()).thenReturn(3);
71         assertEquals(3, withSpy.list.size());
72     }
73 
74     @Test
should_allow_spying_on_interfaces_when_instance_is_concrete()75     public void should_allow_spying_on_interfaces_when_instance_is_concrete() throws Exception {
76         class WithSpy {
77             @Spy
78             List<String> list = new LinkedList<String>();
79         }
80         WithSpy withSpy = new WithSpy();
81 
82         //when
83         MockitoAnnotations.initMocks(withSpy);
84 
85         //then
86         verify(withSpy.list, never()).clear();
87     }
88 
89     @Test
should_report_when_no_arg_less_constructor()90     public void should_report_when_no_arg_less_constructor() throws Exception {
91         class FailingSpy {
92             @Spy
93             NoValidConstructor noValidConstructor;
94         }
95 
96         try {
97             MockitoAnnotations.initMocks(new FailingSpy());
98             fail();
99         } catch (MockitoException e) {
100             assertThat(e.getMessage()).contains("Please ensure that the type")
101                     .contains(NoValidConstructor.class.getSimpleName())
102                     .contains("has a no-arg constructor");
103         }
104     }
105 
106     @Test
should_report_when_constructor_is_explosive()107     public void should_report_when_constructor_is_explosive() throws Exception {
108         class FailingSpy {
109             @Spy
110             ThrowingConstructor throwingConstructor;
111         }
112 
113         try {
114             MockitoAnnotations.initMocks(new FailingSpy());
115             fail();
116         } catch (MockitoException e) {
117             assertThat(e.getMessage()).contains("Unable to create mock instance");
118         }
119     }
120 
121     @Test
should_spy_abstract_class()122     public void should_spy_abstract_class() throws Exception {
123         class SpyAbstractClass {
124             @Spy
125             AbstractList<String> list;
126 
127             List<String> asSingletonList(String s) {
128                 when(list.size()).thenReturn(1);
129                 when(list.get(0)).thenReturn(s);
130                 return list;
131             }
132         }
133         SpyAbstractClass withSpy = new SpyAbstractClass();
134         MockitoAnnotations.initMocks(withSpy);
135         assertEquals(Arrays.asList("a"), withSpy.asSingletonList("a"));
136     }
137 
138     @Test
should_spy_inner_class()139     public void should_spy_inner_class() throws Exception {
140 
141         class WithMockAndSpy {
142             @Spy
143             private InnerStrength strength;
144             @Mock
145             private List<String> list;
146 
147             abstract class InnerStrength {
148                 private final String name;
149 
150                 InnerStrength() {
151                     // Make sure that @Mock fields are always injected before @Spy fields.
152                     assertNotNull(list);
153                     // Make sure constructor is indeed called.
154                     this.name = "inner";
155                 }
156 
157                 abstract String strength();
158 
159                 String fullStrength() {
160                     return name + " " + strength();
161                 }
162             }
163         }
164         WithMockAndSpy outer = new WithMockAndSpy();
165         MockitoAnnotations.initMocks(outer);
166         when(outer.strength.strength()).thenReturn("strength");
167         assertEquals("inner strength", outer.strength.fullStrength());
168     }
169 
170     @Test(expected = IndexOutOfBoundsException.class)
should_reset_spy()171     public void should_reset_spy() throws Exception {
172         spiedList.get(10); // see shouldInitSpy
173     }
174 
175     @Test
should_report_when_enclosing_instance_is_needed()176     public void should_report_when_enclosing_instance_is_needed() throws Exception {
177         class Outer {
178             class Inner {
179             }
180         }
181         class WithSpy {
182             @Spy
183             private Outer.Inner inner;
184         }
185         try {
186             MockitoAnnotations.initMocks(new WithSpy());
187             fail();
188         } catch (MockitoException e) {
189             assertThat(e).hasMessageContaining("@Spy annotation can only initialize inner classes");
190         }
191     }
192 
193     @Test
should_report_private_inner_not_supported()194     public void should_report_private_inner_not_supported() throws Exception {
195         try {
196             MockitoAnnotations.initMocks(new WithInnerPrivate());
197             fail();
198         } catch (MockitoException e) {
199             // Currently fails at instantiation time, because the mock subclass don't have the
200             // 1-arg constructor expected for the outerclass.
201             // org.mockito.internal.creation.instance.ConstructorInstantiator.withParams()
202             assertThat(e).hasMessageContaining("Unable to initialize @Spy annotated field 'spy_field'")
203                     .hasMessageContaining(WithInnerPrivate.InnerPrivate.class.getSimpleName());
204         }
205     }
206 
207     @Test
should_report_private_abstract_inner_not_supported()208     public void should_report_private_abstract_inner_not_supported() throws Exception {
209         try {
210             MockitoAnnotations.initMocks(new WithInnerPrivateAbstract());
211             fail();
212         } catch (MockitoException e) {
213             assertThat(e).hasMessageContaining("@Spy annotation can't initialize private abstract inner classes")
214                     .hasMessageContaining(WithInnerPrivateAbstract.class.getSimpleName())
215                     .hasMessageContaining(WithInnerPrivateAbstract.InnerPrivateAbstract.class.getSimpleName())
216                     .hasMessageContaining("You should augment the visibility of this inner class");
217         }
218     }
219 
220     @Test
should_report_private_static_abstract_inner_not_supported()221     public void should_report_private_static_abstract_inner_not_supported() throws Exception {
222         try {
223             MockitoAnnotations.initMocks(new WithInnerPrivateStaticAbstract());
224             fail();
225         } catch (MockitoException e) {
226             assertThat(e).hasMessageContaining("@Spy annotation can't initialize private abstract inner classes")
227                     .hasMessageContaining(WithInnerPrivateStaticAbstract.class.getSimpleName())
228                     .hasMessageContaining(WithInnerPrivateStaticAbstract.InnerPrivateStaticAbstract.class.getSimpleName())
229                     .hasMessageContaining("You should augment the visibility of this inner class");
230         }
231     }
232 
233     static class WithInnerPrivateStaticAbstract {
234         @Spy
235         private InnerPrivateStaticAbstract spy_field;
236 
237         private static abstract class InnerPrivateStaticAbstract {
238         }
239     }
240     static class WithInnerPrivateAbstract {
241         @Spy
242         private InnerPrivateAbstract spy_field;
243 
some_method()244         public void some_method() {
245             new InnerPrivateConcrete();
246         }
247 
248         private abstract class InnerPrivateAbstract {
249         }
250 
251         private class InnerPrivateConcrete extends InnerPrivateAbstract {
252 
253         }
254     }
255 
256     static class WithInnerPrivate {
257         @Spy
258         private InnerPrivate spy_field;
259 
260         private class InnerPrivate {
261         }
262 
263         private class InnerPrivateSub extends InnerPrivate {}
264     }
265 
266     static class InnerStaticClassWithoutDefinedConstructor {
267     }
268 
269     static class InnerStaticClassWithNoArgConstructor {
InnerStaticClassWithNoArgConstructor()270         InnerStaticClassWithNoArgConstructor() {
271         }
272 
InnerStaticClassWithNoArgConstructor(String f)273         InnerStaticClassWithNoArgConstructor(String f) {
274         }
275     }
276 
277     static class NoValidConstructor {
NoValidConstructor(String f)278         NoValidConstructor(String f) {
279         }
280     }
281 
282     static class ThrowingConstructor {
ThrowingConstructor()283         ThrowingConstructor() {
284             throw new RuntimeException("boo!");
285         }
286     }
287 }
288