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.strictness; 6 7 import static org.assertj.core.api.Assertions.assertThatThrownBy; 8 import static org.junit.Assert.assertEquals; 9 import static org.mockito.Mockito.lenient; 10 import static org.mockito.Mockito.mock; 11 import static org.mockito.Mockito.spy; 12 import static org.mockito.Mockito.verifyNoMoreInteractions; 13 import static org.mockito.Mockito.when; 14 15 import org.assertj.core.api.ThrowableAssert; 16 import org.junit.After; 17 import org.junit.Before; 18 import org.junit.Test; 19 import org.mockito.AdditionalAnswers; 20 import org.mockito.Mock; 21 import org.mockito.Mockito; 22 import org.mockito.MockitoSession; 23 import org.mockito.exceptions.misusing.PotentialStubbingProblem; 24 import org.mockito.exceptions.misusing.UnnecessaryStubbingException; 25 import org.mockito.exceptions.verification.NoInteractionsWanted; 26 import org.mockito.quality.Strictness; 27 import org.mockitousage.IMethods; 28 import org.mockitoutil.TestBase; 29 30 public class StrictnessPerStubbingTest { 31 32 MockitoSession mockito; 33 @Mock IMethods mock; 34 35 @Before before()36 public void before() { 37 mockito = 38 Mockito.mockitoSession() 39 .initMocks(this) 40 .strictness(Strictness.STRICT_STUBS) 41 .startMocking(); 42 } 43 44 @Test potential_stubbing_problem()45 public void potential_stubbing_problem() { 46 // when 47 when(mock.simpleMethod("1")).thenReturn("1"); 48 lenient().when(mock.differentMethod("2")).thenReturn("2"); 49 50 // then on lenient stubbing, we can call it with different argument: 51 mock.differentMethod("200"); 52 53 // but on strict stubbing, we cannot: 54 assertThatThrownBy( 55 new ThrowableAssert.ThrowingCallable() { 56 @Override 57 public void call() throws Throwable { 58 ProductionCode.simpleMethod(mock, "100"); 59 } 60 }) 61 .isInstanceOf(PotentialStubbingProblem.class); 62 } 63 64 @Test doReturn_syntax()65 public void doReturn_syntax() { 66 // when 67 lenient().doReturn("2").doReturn("3").when(mock).simpleMethod(1); 68 69 // then on lenient stubbing, we can call it with different argument: 70 mock.simpleMethod(200); 71 72 // and stubbing works, too: 73 assertEquals("2", mock.simpleMethod(1)); 74 assertEquals("3", mock.simpleMethod(1)); 75 } 76 77 @Test doReturn_varargs_syntax()78 public void doReturn_varargs_syntax() { 79 // when 80 lenient().doReturn("2", "3").when(mock).simpleMethod(1); 81 82 // then on lenient stubbing, we can call it with different argument with no exception: 83 mock.simpleMethod(200); 84 85 // and stubbing works, too: 86 assertEquals("2", mock.simpleMethod(1)); 87 assertEquals("3", mock.simpleMethod(1)); 88 } 89 90 @Test doThrow_syntax()91 public void doThrow_syntax() { 92 // when 93 lenient() 94 .doThrow(IllegalArgumentException.class) 95 .doThrow(IllegalStateException.class) 96 .when(mock) 97 .simpleMethod(1); 98 99 // then on lenient stubbing, we can call it with different argument with no exception: 100 mock.simpleMethod(200); 101 102 // and stubbing works, too: 103 assertThatThrownBy( 104 new ThrowableAssert.ThrowingCallable() { 105 public void call() throws Throwable { 106 mock.simpleMethod(1); 107 } 108 }) 109 .isInstanceOf(IllegalArgumentException.class); 110 111 // testing consecutive call: 112 assertThatThrownBy( 113 new ThrowableAssert.ThrowingCallable() { 114 public void call() throws Throwable { 115 mock.simpleMethod(1); 116 } 117 }) 118 .isInstanceOf(IllegalStateException.class); 119 } 120 121 @Test doThrow_vararg_syntax()122 public void doThrow_vararg_syntax() { 123 // when 124 lenient() 125 .doThrow(IllegalArgumentException.class, IllegalStateException.class) 126 .when(mock) 127 .simpleMethod(1); 128 129 // then on lenient stubbing, we can call it with different argument with no exception: 130 mock.simpleMethod(200); 131 132 // and stubbing works, too: 133 assertThatThrownBy( 134 new ThrowableAssert.ThrowingCallable() { 135 public void call() throws Throwable { 136 mock.simpleMethod(1); 137 } 138 }) 139 .isInstanceOf(IllegalArgumentException.class); 140 141 // testing consecutive call: 142 assertThatThrownBy( 143 new ThrowableAssert.ThrowingCallable() { 144 public void call() throws Throwable { 145 mock.simpleMethod(1); 146 } 147 }) 148 .isInstanceOf(IllegalStateException.class); 149 } 150 151 @Test doThrow_instance_vararg_syntax()152 public void doThrow_instance_vararg_syntax() { 153 // when 154 lenient() 155 .doThrow(new IllegalArgumentException(), new IllegalStateException()) 156 .when(mock) 157 .simpleMethod(1); 158 159 // then on lenient stubbing, we can call it with different argument with no exception: 160 mock.simpleMethod(200); 161 162 // and stubbing works, too: 163 assertThatThrownBy( 164 new ThrowableAssert.ThrowingCallable() { 165 public void call() throws Throwable { 166 mock.simpleMethod(1); 167 } 168 }) 169 .isInstanceOf(IllegalArgumentException.class); 170 171 // testing consecutive call: 172 assertThatThrownBy( 173 new ThrowableAssert.ThrowingCallable() { 174 public void call() throws Throwable { 175 mock.simpleMethod(1); 176 } 177 }) 178 .isInstanceOf(IllegalStateException.class); 179 } 180 181 static class Counter { increment(int x)182 int increment(int x) { 183 return x + 1; 184 } 185 scream(String message)186 void scream(String message) { 187 throw new RuntimeException(message); 188 } 189 } 190 191 @Test doCallRealMethod_syntax()192 public void doCallRealMethod_syntax() { 193 // when 194 Counter mock = mock(Counter.class); 195 lenient().doCallRealMethod().when(mock).increment(1); 196 197 // then no exception and default return value if we call it with different arg: 198 assertEquals(0, mock.increment(0)); 199 200 // and real method is called when using correct arg: 201 assertEquals(2, mock.increment(1)); 202 } 203 204 @Test doNothing_syntax()205 public void doNothing_syntax() { 206 // when 207 final Counter spy = spy(Counter.class); 208 lenient().doNothing().when(spy).scream("1"); 209 210 // then no stubbing exception and real method is called if we call stubbed method with 211 // different arg: 212 assertThatThrownBy( 213 new ThrowableAssert.ThrowingCallable() { 214 @Override 215 public void call() throws Throwable { 216 spy.scream("2"); 217 } 218 }) 219 .hasMessage("2"); 220 221 // and we do nothing when stubbing called with correct arg: 222 spy.scream("1"); 223 } 224 225 @Test doAnswer_syntax()226 public void doAnswer_syntax() { 227 // when 228 lenient().doAnswer(AdditionalAnswers.returnsFirstArg()).when(mock).simpleMethod("1"); 229 230 // then on lenient stubbing, we can call it with different argument: 231 mock.simpleMethod("200"); 232 233 // and stubbing works, too: 234 assertEquals("1", mock.simpleMethod("1")); 235 } 236 237 @Test unnecessary_stubbing()238 public void unnecessary_stubbing() { 239 // when 240 when(mock.simpleMethod("1")).thenReturn("1"); 241 lenient().when(mock.differentMethod("2")).thenReturn("2"); 242 243 // then unnecessary stubbing flags method only on the strict stubbing: 244 assertThatThrownBy( 245 new ThrowableAssert.ThrowingCallable() { 246 @Override 247 public void call() throws Throwable { 248 mockito.finishMocking(); 249 } 250 }) 251 .isInstanceOf(UnnecessaryStubbingException.class) 252 .hasMessageContaining("1. -> ") 253 // good enough to prove that we're flagging just one unnecessary stubbing: 254 // TODO 792: this assertion is duplicated with StrictnessPerMockTest 255 .isNot(TestBase.hasMessageContaining("2. ->")); 256 } 257 258 @Test unnecessary_stubbing_with_doReturn()259 public void unnecessary_stubbing_with_doReturn() { 260 // when 261 lenient().doReturn("2").when(mock).differentMethod("2"); 262 263 // then no exception is thrown: 264 mockito.finishMocking(); 265 } 266 267 @Test verify_no_more_invocations()268 public void verify_no_more_invocations() { 269 // when 270 when(mock.simpleMethod("1")).thenReturn("1"); 271 lenient().when(mock.differentMethod("2")).thenReturn("2"); 272 273 // and: 274 mock.simpleMethod("1"); 275 mock.differentMethod("200"); // <- different arg 276 277 // then 'verifyNoMoreInteractions' flags the lenient stubbing (called with different arg) 278 // and reports it with [?] in the exception message 279 assertThatThrownBy( 280 new ThrowableAssert.ThrowingCallable() { 281 @Override 282 public void call() throws Throwable { 283 verifyNoMoreInteractions(mock); 284 } 285 }) 286 .isInstanceOf(NoInteractionsWanted.class) 287 .hasMessageContaining("1. ->") 288 .hasMessageContaining("2. [?]->"); 289 // TODO 792: assertion duplicated with StrictnessPerMockTest 290 // and we should use assertions based on content of the exception rather than the string 291 } 292 293 @After after()294 public void after() { 295 mockito.finishMocking(); 296 } 297 } 298