1 /*
2  * Copyright (c) 2007 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 
6 package org.mockitousage.spies;
7 
8 import org.assertj.core.api.Assertions;
9 import org.junit.Before;
10 import org.junit.Test;
11 import org.mockitoutil.TestBase;
12 
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.fail;
15 import static org.mockito.Mockito.doThrow;
16 import static org.mockito.Mockito.spy;
17 import static org.mockito.Mockito.verify;
18 import static org.mockito.Mockito.when;
19 import static org.mockitoutil.Conditions.methodsInStackTrace;
20 
21 @SuppressWarnings("unchecked")
22 public class PartialMockingWithSpiesTest extends TestBase {
23 
24     @Before
pleaseMakeStackTracesClean()25     public void pleaseMakeStackTracesClean() {
26         makeStackTracesClean();
27     }
28 
29     class InheritMe {
30         private String inherited = "100$";
getInherited()31         protected String getInherited() {
32             return inherited;
33         }
34     }
35 
36     class Person extends InheritMe {
37         private final Name defaultName = new Name("Default name");
38 
getName()39         public String getName() {
40             return guessName().name;
41         }
42 
guessName()43         Name guessName() {
44             return defaultName;
45         }
46 
howMuchDidYouInherit()47         public String howMuchDidYouInherit() {
48             return getInherited();
49         }
50 
getNameButDelegateToMethodThatThrows()51         public String getNameButDelegateToMethodThatThrows() {
52             throwSomeException();
53             return guessName().name;
54         }
55 
throwSomeException()56         private void throwSomeException() {
57             throw new RuntimeException("boo");
58         }
59     }
60 
61     class Name {
62         private final String name;
63 
Name(String name)64         public Name(String name) {
65             this.name = name;
66         }
67     }
68 
69     Person spy = spy(new Person());
70 
71     @Test
shouldCallRealMethdsEvenDelegatedToOtherSelfMethod()72     public void shouldCallRealMethdsEvenDelegatedToOtherSelfMethod() {
73         // when
74         String name = spy.getName();
75 
76         // then
77         assertEquals("Default name", name);
78     }
79 
80     @Test
shouldAllowStubbingOfMethodsThatDelegateToOtherMethods()81     public void shouldAllowStubbingOfMethodsThatDelegateToOtherMethods() {
82         // when
83         when(spy.getName()).thenReturn("foo");
84 
85         // then
86         assertEquals("foo", spy.getName());
87     }
88 
89     @Test
shouldAllowStubbingWithThrowablesMethodsThatDelegateToOtherMethods()90     public void shouldAllowStubbingWithThrowablesMethodsThatDelegateToOtherMethods() {
91         // when
92         doThrow(new RuntimeException("appetite for destruction"))
93             .when(spy).getNameButDelegateToMethodThatThrows();
94 
95         // then
96         try {
97             spy.getNameButDelegateToMethodThatThrows();
98             fail();
99         } catch(Exception e) {
100             assertEquals("appetite for destruction", e.getMessage());
101         }
102     }
103 
104     @Test
shouldStackTraceGetFilteredOnUserExceptions()105     public void shouldStackTraceGetFilteredOnUserExceptions() {
106         try {
107             // when
108             spy.getNameButDelegateToMethodThatThrows();
109             fail();
110         } catch (Throwable t) {
111             // then
112             Assertions.assertThat(t).has(methodsInStackTrace(
113                     "throwSomeException",
114                     "getNameButDelegateToMethodThatThrows",
115                     "shouldStackTraceGetFilteredOnUserExceptions"
116                     ));
117         }
118     }
119 
120 //    @Test //manual verification
verifyTheStackTrace()121     public void verifyTheStackTrace() {
122         spy.getNameButDelegateToMethodThatThrows();
123     }
124 
125     @Test
shouldVerify()126     public void shouldVerify() {
127         // when
128         spy.getName();
129 
130         // then
131         verify(spy).guessName();
132     }
133 
134     @Test
shouldStub()135     public void shouldStub() {
136         // given
137         when(spy.guessName()).thenReturn(new Name("John"));
138         // when
139         String name = spy.getName();
140         // then
141         assertEquals("John", name);
142     }
143 
144     @Test
shouldDealWithPrivateFieldsOfSubclasses()145     public void shouldDealWithPrivateFieldsOfSubclasses() {
146         assertEquals("100$", spy.howMuchDidYouInherit());
147     }
148 }
149