| /* |
| * Copyright (c) 2007 Mockito contributors |
| * This program is made available under the terms of the MIT License. |
| */ |
| |
| package org.mockitousage.strictness; |
| |
| import org.assertj.core.api.ThrowableAssert; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.mockito.AdditionalAnswers; |
| import org.mockito.Mock; |
| import org.mockito.Mockito; |
| import org.mockito.MockitoSession; |
| import org.mockito.exceptions.misusing.PotentialStubbingProblem; |
| import org.mockito.exceptions.misusing.UnnecessaryStubbingException; |
| import org.mockito.exceptions.verification.NoInteractionsWanted; |
| import org.mockito.quality.Strictness; |
| import org.mockitousage.IMethods; |
| import org.mockitoutil.TestBase; |
| |
| import static org.assertj.core.api.Assertions.assertThatThrownBy; |
| import static org.junit.Assert.assertEquals; |
| import static org.mockito.Mockito.lenient; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.spy; |
| import static org.mockito.Mockito.verifyNoMoreInteractions; |
| import static org.mockito.Mockito.when; |
| |
| public class StrictnessPerStubbingTest { |
| |
| MockitoSession mockito; |
| @Mock IMethods mock; |
| |
| @Before |
| public void before() { |
| mockito = Mockito.mockitoSession().initMocks(this).strictness(Strictness.STRICT_STUBS).startMocking(); |
| } |
| |
| @Test |
| public void potential_stubbing_problem() { |
| //when |
| when(mock.simpleMethod("1")).thenReturn("1"); |
| lenient().when(mock.differentMethod("2")).thenReturn("2"); |
| |
| //then on lenient stubbing, we can call it with different argument: |
| mock.differentMethod("200"); |
| |
| //but on strict stubbing, we cannot: |
| assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { |
| @Override |
| public void call() throws Throwable { |
| mock.simpleMethod("100"); |
| } |
| }).isInstanceOf(PotentialStubbingProblem.class); |
| } |
| |
| @Test |
| public void doReturn_syntax() { |
| //when |
| lenient().doReturn("2").doReturn("3") |
| .when(mock).simpleMethod(1); |
| |
| //then on lenient stubbing, we can call it with different argument: |
| mock.simpleMethod(200); |
| |
| //and stubbing works, too: |
| assertEquals("2", mock.simpleMethod(1)); |
| assertEquals("3", mock.simpleMethod(1)); |
| } |
| |
| @Test |
| public void doReturn_varargs_syntax() { |
| //when |
| lenient().doReturn("2", "3") |
| .when(mock).simpleMethod(1); |
| |
| //then on lenient stubbing, we can call it with different argument with no exception: |
| mock.simpleMethod(200); |
| |
| //and stubbing works, too: |
| assertEquals("2", mock.simpleMethod(1)); |
| assertEquals("3", mock.simpleMethod(1)); |
| } |
| |
| @Test |
| public void doThrow_syntax() { |
| //when |
| lenient() |
| .doThrow(IllegalArgumentException.class) |
| .doThrow(IllegalStateException.class) |
| .when(mock).simpleMethod(1); |
| |
| //then on lenient stubbing, we can call it with different argument with no exception: |
| mock.simpleMethod(200); |
| |
| //and stubbing works, too: |
| assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { |
| public void call() throws Throwable { |
| mock.simpleMethod(1); |
| } |
| }).isInstanceOf(IllegalArgumentException.class); |
| |
| //testing consecutive call: |
| assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { |
| public void call() throws Throwable { |
| mock.simpleMethod(1); |
| } |
| }).isInstanceOf(IllegalStateException.class); |
| } |
| |
| @Test |
| public void doThrow_vararg_syntax() { |
| //when |
| lenient() |
| .doThrow(IllegalArgumentException.class, IllegalStateException.class) |
| .when(mock).simpleMethod(1); |
| |
| //then on lenient stubbing, we can call it with different argument with no exception: |
| mock.simpleMethod(200); |
| |
| //and stubbing works, too: |
| assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { |
| public void call() throws Throwable { |
| mock.simpleMethod(1); |
| } |
| }).isInstanceOf(IllegalArgumentException.class); |
| |
| //testing consecutive call: |
| assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { |
| public void call() throws Throwable { |
| mock.simpleMethod(1); |
| } |
| }).isInstanceOf(IllegalStateException.class); |
| } |
| |
| @Test |
| public void doThrow_instance_vararg_syntax() { |
| //when |
| lenient() |
| .doThrow(new IllegalArgumentException(), new IllegalStateException()) |
| .when(mock).simpleMethod(1); |
| |
| //then on lenient stubbing, we can call it with different argument with no exception: |
| mock.simpleMethod(200); |
| |
| //and stubbing works, too: |
| assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { |
| public void call() throws Throwable { |
| mock.simpleMethod(1); |
| } |
| }).isInstanceOf(IllegalArgumentException.class); |
| |
| //testing consecutive call: |
| assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { |
| public void call() throws Throwable { |
| mock.simpleMethod(1); |
| } |
| }).isInstanceOf(IllegalStateException.class); |
| } |
| |
| static class Counter { |
| int increment(int x) { |
| return x + 1; |
| } |
| void scream(String message) { |
| throw new RuntimeException(message); |
| } |
| } |
| |
| @Test |
| public void doCallRealMethod_syntax() { |
| //when |
| Counter mock = mock(Counter.class); |
| lenient().doCallRealMethod().when(mock).increment(1); |
| |
| //then no exception and default return value if we call it with different arg: |
| assertEquals(0, mock.increment(0)); |
| |
| //and real method is called when using correct arg: |
| assertEquals(2, mock.increment(1)); |
| } |
| |
| @Test |
| public void doNothing_syntax() { |
| //when |
| final Counter spy = spy(Counter.class); |
| lenient().doNothing().when(spy).scream("1"); |
| |
| //then no stubbing exception and real method is called if we call stubbed method with different arg: |
| assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { |
| @Override |
| public void call() throws Throwable { |
| spy.scream("2"); |
| } |
| }).hasMessage("2"); |
| |
| //and we do nothing when stubbing called with correct arg: |
| spy.scream("1"); |
| } |
| |
| @Test |
| public void doAnswer_syntax() { |
| //when |
| lenient().doAnswer(AdditionalAnswers.returnsFirstArg()).when(mock).simpleMethod("1"); |
| |
| //then on lenient stubbing, we can call it with different argument: |
| mock.simpleMethod("200"); |
| |
| //and stubbing works, too: |
| assertEquals("1", mock.simpleMethod("1")); |
| } |
| |
| @Test |
| public void unnecessary_stubbing() { |
| //when |
| when(mock.simpleMethod("1")).thenReturn("1"); |
| lenient().when(mock.differentMethod("2")).thenReturn("2"); |
| |
| //then unnecessary stubbing flags method only on the strict stubbing: |
| assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { |
| @Override |
| public void call() throws Throwable { |
| mockito.finishMocking(); |
| } |
| }).isInstanceOf(UnnecessaryStubbingException.class) |
| .hasMessageContaining("1. -> ") |
| //good enough to prove that we're flagging just one unnecessary stubbing: |
| //TODO 792: this assertion is duplicated with StrictnessPerMockTest |
| .isNot(TestBase.hasMessageContaining("2. ->")); |
| } |
| |
| @Test |
| public void unnecessary_stubbing_with_doReturn() { |
| //when |
| lenient().doReturn("2").when(mock).differentMethod("2"); |
| |
| //then no exception is thrown: |
| mockito.finishMocking(); |
| } |
| |
| @Test |
| public void verify_no_more_invocations() { |
| //when |
| when(mock.simpleMethod("1")).thenReturn("1"); |
| lenient().when(mock.differentMethod("2")).thenReturn("2"); |
| |
| //and: |
| mock.simpleMethod("1"); |
| mock.differentMethod("200"); // <- different arg |
| |
| //then 'verifyNoMoreInteractions' flags the lenient stubbing (called with different arg) |
| //and reports it with [?] in the exception message |
| assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { |
| @Override |
| public void call() throws Throwable { |
| verifyNoMoreInteractions(mock); |
| } |
| }).isInstanceOf(NoInteractionsWanted.class) |
| .hasMessageContaining("1. ->") |
| .hasMessageContaining("2. [?]->"); |
| //TODO 792: assertion duplicated with StrictnessPerMockTest |
| // and we should use assertions based on content of the exception rather than the string |
| } |
| |
| @After |
| public void after() { |
| mockito.finishMocking(); |
| } |
| } |