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.stubbing; 6 7 import org.assertj.core.api.Assertions; 8 import org.junit.Test; 9 import org.mockito.InOrder; 10 import org.mockito.exceptions.verification.TooManyActualInvocations; 11 import org.mockitoutil.TestBase; 12 13 import javax.net.SocketFactory; 14 import java.io.ByteArrayOutputStream; 15 import java.io.OutputStream; 16 import java.net.Socket; 17 import java.util.List; 18 import java.util.Locale; 19 20 import static org.junit.Assert.*; 21 import static org.mockito.BDDMockito.given; 22 import static org.mockito.Mockito.*; 23 24 25 public class DeepStubbingTest extends TestBase { 26 27 static class Person { 28 Address address; 29 30 public Address getAddress() { 31 return address; 32 } 33 34 public Address getAddress(String addressName) { 35 return address; 36 } 37 38 public FinalClass getFinalClass() { 39 return null; 40 } 41 } 42 43 static class Address { 44 Street street; 45 46 public Street getStreet() { 47 return street; 48 } 49 50 public Street getStreet(Locale locale) { 51 return street; 52 } 53 } 54 55 static class Street { 56 String name; 57 58 public String getName() { 59 return name; 60 } 61 62 public String getLongName() { 63 return name; 64 } 65 } 66 67 static final class FinalClass {} 68 69 interface First { 70 Second getSecond(); 71 72 String getString(); 73 } 74 75 interface Second extends List<String> {} 76 77 @Test 78 public void myTest() throws Exception { 79 SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); 80 when(sf.createSocket(anyString(), eq(80))).thenReturn(null); 81 sf.createSocket("what", 80); 82 } 83 84 @Test 85 public void simpleCase() throws Exception { 86 OutputStream out = new ByteArrayOutputStream(); 87 Socket socket = mock(Socket.class); 88 when(socket.getOutputStream()).thenReturn(out); 89 90 assertSame(out, socket.getOutputStream()); 91 } 92 93 /** 94 * Test that deep stubbing works for one intermediate level 95 */ 96 @Test 97 public void oneLevelDeep() throws Exception { 98 OutputStream out = new ByteArrayOutputStream(); 99 100 SocketFactory socketFactory = mock(SocketFactory.class, RETURNS_DEEP_STUBS); 101 when(socketFactory.createSocket().getOutputStream()).thenReturn(out); 102 103 assertSame(out, socketFactory.createSocket().getOutputStream()); 104 } 105 106 /** 107 * Test that stubbing of two mocks stubs don't interfere 108 */ 109 @Test 110 public void interactions() throws Exception { 111 OutputStream out1 = new ByteArrayOutputStream(); 112 OutputStream out2 = new ByteArrayOutputStream(); 113 114 SocketFactory sf1 = mock(SocketFactory.class, RETURNS_DEEP_STUBS); 115 when(sf1.createSocket().getOutputStream()).thenReturn(out1); 116 117 SocketFactory sf2 = mock(SocketFactory.class, RETURNS_DEEP_STUBS); 118 when(sf2.createSocket().getOutputStream()).thenReturn(out2); 119 120 assertSame(out1, sf1.createSocket().getOutputStream()); 121 assertSame(out2, sf2.createSocket().getOutputStream()); 122 } 123 124 /** 125 * Test that stubbing of methods of different arguments don't interfere 126 */ 127 @Test 128 public void withArguments() throws Exception { 129 OutputStream out1 = new ByteArrayOutputStream(); 130 OutputStream out2 = new ByteArrayOutputStream(); 131 OutputStream out3 = new ByteArrayOutputStream(); 132 133 SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); 134 when(sf.createSocket().getOutputStream()).thenReturn(out1); 135 when(sf.createSocket("google.com", 80).getOutputStream()).thenReturn(out2); 136 when(sf.createSocket("stackoverflow.com", 80).getOutputStream()).thenReturn(out3); 137 138 assertSame(out1, sf.createSocket().getOutputStream()); 139 assertSame(out2, sf.createSocket("google.com", 80).getOutputStream()); 140 assertSame(out3, sf.createSocket("stackoverflow.com", 80).getOutputStream()); 141 } 142 143 /** 144 * Test that deep stubbing work with argument patterns 145 */ 146 @Test 147 public void withAnyPatternArguments() throws Exception { 148 OutputStream out = new ByteArrayOutputStream(); 149 150 //TODO: should not use javax in case it changes 151 SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); 152 when(sf.createSocket(anyString(), anyInt()).getOutputStream()).thenReturn(out); 153 154 assertSame(out, sf.createSocket("google.com", 80).getOutputStream()); 155 assertSame(out, sf.createSocket("stackoverflow.com", 8080).getOutputStream()); 156 } 157 158 /** 159 * Test that deep stubbing work with argument patterns 160 */ 161 @Test 162 public void withComplexPatternArguments() throws Exception { 163 OutputStream out1 = new ByteArrayOutputStream(); 164 OutputStream out2 = new ByteArrayOutputStream(); 165 166 SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); 167 when(sf.createSocket(anyString(), eq(80)).getOutputStream()).thenReturn(out1); 168 when(sf.createSocket(anyString(), eq(8080)).getOutputStream()).thenReturn(out2); 169 170 assertSame(out2, sf.createSocket("stackoverflow.com", 8080).getOutputStream()); 171 assertSame(out1, sf.createSocket("google.com", 80).getOutputStream()); 172 assertSame(out2, sf.createSocket("google.com", 8080).getOutputStream()); 173 assertSame(out1, sf.createSocket("stackoverflow.com", 80).getOutputStream()); 174 } 175 176 /** 177 * Test that deep stubbing work with primitive expected values 178 */ 179 @Test 180 public void withSimplePrimitive() throws Exception { 181 int a = 32; 182 183 SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); 184 when(sf.createSocket().getPort()).thenReturn(a); 185 186 assertEquals(a, sf.createSocket().getPort()); 187 } 188 189 /** 190 * Test that deep stubbing work with primitive expected values with 191 * pattern method arguments 192 */ 193 @Test 194 public void withPatternPrimitive() throws Exception { 195 int a = 12, b = 23, c = 34; 196 197 SocketFactory sf = mock(SocketFactory.class, RETURNS_DEEP_STUBS); 198 when(sf.createSocket(eq("stackoverflow.com"), eq(80)).getPort()).thenReturn(a); 199 when(sf.createSocket(eq("google.com"), anyInt()).getPort()).thenReturn(b); 200 when(sf.createSocket(eq("stackoverflow.com"), eq(8080)).getPort()).thenReturn(c); 201 202 assertEquals(b, sf.createSocket("google.com", 80).getPort()); 203 assertEquals(c, sf.createSocket("stackoverflow.com", 8080).getPort()); 204 assertEquals(a, sf.createSocket("stackoverflow.com", 80).getPort()); 205 } 206 207 Person person = mock(Person.class, RETURNS_DEEP_STUBS); 208 209 @Test 210 public void shouldStubbingBasicallyWorkFine() throws Exception { 211 //given 212 given(person.getAddress().getStreet().getName()).willReturn("Norymberska"); 213 214 //when 215 String street = person.getAddress().getStreet().getName(); 216 217 //then 218 assertEquals("Norymberska", street); 219 } 220 221 @Test 222 public void shouldVerificationBasicallyWorkFine() throws Exception { 223 //given 224 person.getAddress().getStreet().getName(); 225 226 //then 227 verify(person.getAddress().getStreet()).getName(); 228 } 229 230 @Test 231 public void verification_work_with_argument_Matchers_in_nested_calls() throws Exception { 232 //given 233 person.getAddress("111 Mock Lane").getStreet(); 234 person.getAddress("111 Mock Lane").getStreet(Locale.ITALIAN).getName(); 235 236 //then 237 verify(person.getAddress(anyString())).getStreet(); 238 verify(person.getAddress(anyString()).getStreet(Locale.CHINESE), never()).getName(); 239 verify(person.getAddress(anyString()).getStreet(eq(Locale.ITALIAN))).getName(); 240 } 241 242 @Test 243 public void deep_stub_return_same_mock_instance_if_invocation_matchers_matches() throws Exception { 244 when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep"); 245 246 person.getAddress("the docks").getStreet().getName(); 247 248 assertSame(person.getAddress("the docks").getStreet(), person.getAddress(anyString()).getStreet()); 249 assertSame(person.getAddress(anyString()).getStreet(), person.getAddress(anyString()).getStreet()); 250 assertSame(person.getAddress("the docks").getStreet(), person.getAddress("the docks").getStreet()); 251 assertSame(person.getAddress(anyString()).getStreet(), person.getAddress("the docks").getStreet()); 252 assertSame(person.getAddress("111 Mock Lane").getStreet(), person.getAddress("the docks").getStreet()); 253 } 254 255 @Test 256 public void times_never_atLeast_atMost_verificationModes_should_work() throws Exception { 257 when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep"); 258 259 person.getAddress("the docks").getStreet().getName(); 260 person.getAddress("the docks").getStreet().getName(); 261 person.getAddress("the docks").getStreet().getName(); 262 person.getAddress("the docks").getStreet(Locale.ITALIAN).getName(); 263 264 verify(person.getAddress("the docks").getStreet(), times(3)).getName(); 265 verify(person.getAddress("the docks").getStreet(Locale.CHINESE), never()).getName(); 266 verify(person.getAddress("the docks").getStreet(Locale.ITALIAN), atMost(1)).getName(); 267 } 268 269 270 @Test 271 public void inOrder_only_work_on_the_very_last_mock_but_it_works() throws Exception { 272 when(person.getAddress(anyString()).getStreet().getName()).thenReturn("deep"); 273 when(person.getAddress(anyString()).getStreet(Locale.ITALIAN).getName()).thenReturn("deep"); 274 when(person.getAddress(anyString()).getStreet(Locale.CHINESE).getName()).thenReturn("deep"); 275 276 person.getAddress("the docks").getStreet().getName(); 277 person.getAddress("the docks").getStreet().getLongName(); 278 person.getAddress("the docks").getStreet(Locale.ITALIAN).getName(); 279 person.getAddress("the docks").getStreet(Locale.CHINESE).getName(); 280 281 InOrder inOrder = inOrder( 282 person.getAddress("the docks").getStreet(), 283 person.getAddress("the docks").getStreet(Locale.CHINESE), 284 person.getAddress("the docks").getStreet(Locale.ITALIAN) 285 ); 286 inOrder.verify(person.getAddress("the docks").getStreet(), times(1)).getName(); 287 inOrder.verify(person.getAddress("the docks").getStreet()).getLongName(); 288 inOrder.verify(person.getAddress("the docks").getStreet(Locale.ITALIAN), atLeast(1)).getName(); 289 inOrder.verify(person.getAddress("the docks").getStreet(Locale.CHINESE)).getName(); 290 } 291 292 @Test 293 public void verificationMode_only_work_on_the_last_returned_mock() throws Exception { 294 // 1st invocation on Address mock (stubbing) 295 when(person.getAddress("the docks").getStreet().getName()).thenReturn("deep"); 296 297 // 2nd invocation on Address mock (real) 298 person.getAddress("the docks").getStreet().getName(); 299 // 3rd invocation on Address mock (verification) 300 // (Address mock is not in verification mode) 301 verify(person.getAddress("the docks").getStreet()).getName(); 302 303 try { 304 verify(person.getAddress("the docks"), times(1)).getStreet(); 305 fail(); 306 } catch (TooManyActualInvocations e) { 307 Assertions.assertThat(e.getMessage()) 308 .contains("Wanted 1 time") 309 .contains("But was 3 times"); 310 } 311 } 312 313 @Test 314 public void shouldFailGracefullyWhenClassIsFinal() throws Exception { 315 //when 316 FinalClass value = new FinalClass(); 317 given(person.getFinalClass()).willReturn(value); 318 319 //then 320 assertEquals(value, person.getFinalClass()); 321 } 322 323 @Test 324 public void deep_stub_does_not_try_to_mock_generic_final_classes() { 325 First first = mock(First.class, RETURNS_DEEP_STUBS); 326 assertNull(first.getString()); 327 assertNull(first.getSecond().get(0)); 328 } 329 } 330