/* * Copyright (c) 2007 Mockito contributors * This program is made available under the terms of the MIT License. */ package org.mockitousage.stubbing; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.hamcrest.CoreMatchers.sameInstance; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import java.io.IOException; import java.io.Reader; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import org.assertj.core.api.Assertions; import org.assertj.core.api.ThrowableAssert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.exceptions.base.MockitoException; import org.mockito.exceptions.verification.NoInteractionsWanted; import org.mockito.exceptions.verification.WantedButNotInvoked; import org.mockitousage.IMethods; import org.mockitoutil.TestBase; @SuppressWarnings({ "serial", "unchecked", "rawtypes" }) public class StubbingWithThrowablesTest extends TestBase { private LinkedList mock; private Map mockTwo; @Rule public ExpectedException exception = ExpectedException.none(); @Before public void setup() { mock = mock(LinkedList.class); mockTwo = mock(HashMap.class); } @Test public void throws_same_exception_consecutively() { when(mock.add("")).thenThrow(new ExceptionOne()); //1st invocation Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { public void call() { mock.add(""); } }).isInstanceOf(ExceptionOne.class); mock.add("1"); //2nd invocation Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { public void call() { mock.add(""); } }).isInstanceOf(ExceptionOne.class); } @Test public void throws_same_exception_consecutively_with_doThrow() { doThrow(new ExceptionOne()).when(mock).clear(); //1st invocation Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { public void call() { mock.clear(); } }).isInstanceOf(ExceptionOne.class); mock.add("1"); //2nd invocation Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() { public void call() { mock.clear(); } }).isInstanceOf(ExceptionOne.class); } @Test public void shouldStubWithThrowable() throws Exception { IllegalArgumentException expected = new IllegalArgumentException("thrown by mock"); when(mock.add("throw")).thenThrow(expected); exception.expect(sameInstance(expected)); mock.add("throw"); } @Test public void shouldSetThrowableToVoidMethod() throws Exception { IllegalArgumentException expected = new IllegalArgumentException("thrown by mock"); doThrow(expected).when(mock).clear(); exception.expect(sameInstance(expected)); mock.clear(); } @Test public void shouldLastStubbingVoidBeImportant() throws Exception { doThrow(new ExceptionOne()).when(mock).clear(); doThrow(new ExceptionTwo()).when(mock).clear(); exception.expect(ExceptionTwo.class); mock.clear(); } @Test public void shouldFailStubbingThrowableOnTheSameInvocationDueToAcceptableLimitation() throws Exception { when(mock.size()).thenThrow(new ExceptionOne()); exception.expect(ExceptionOne.class); when(mock.size()).thenThrow(new ExceptionTwo()); } @Test public void shouldAllowSettingCheckedException() throws Exception { Reader reader = mock(Reader.class); IOException ioException = new IOException(); when(reader.read()).thenThrow(ioException); exception.expect(sameInstance(ioException)); reader.read(); } @Test public void shouldAllowSettingError() throws Exception { Error error = new Error(); when(mock.add("quake")).thenThrow(error); exception.expect(Error.class); mock.add("quake"); } @Test public void shouldNotAllowNullExceptionType() { exception.expect(MockitoException.class); exception.expectMessage("Cannot stub with null throwable"); when(mock.add(null)).thenThrow((Exception) null); } @Test public void shouldInstantiateExceptionClassOnInteraction() { when(mock.add(null)).thenThrow(NaughtyException.class); exception.expect(NaughtyException.class); mock.add(null); } @Test public void shouldInstantiateExceptionClassWithOngoingStubbingOnInteraction() { doThrow(NaughtyException.class).when(mock).add(null); exception.expect(NaughtyException.class); mock.add(null); } @Test public void shouldNotAllowSettingInvalidCheckedException() { exception.expect(MockitoException.class); exception.expectMessage("Checked exception is invalid for this method"); when(mock.add("monkey island")).thenThrow(new Exception()); } @Test public void shouldNotAllowSettingNullThrowable() { exception.expect(MockitoException.class); exception.expectMessage("Cannot stub with null throwable"); when(mock.add("monkey island")).thenThrow((Throwable) null); } @Test public void shouldNotAllowSettingNullThrowableArray() { exception.expect(MockitoException.class); exception.expectMessage("Cannot stub with null throwable"); when(mock.add("monkey island")).thenThrow((Throwable[]) null); } @Test public void shouldNotAllowSettingNullThrowableClass() { exception.expect(MockitoException.class); exception.expectMessage("Exception type cannot be null"); when(mock.isEmpty()).thenThrow((Class) null); } @Test public void shouldNotAllowSettingNullThrowableClasses() { exception.expect(MockitoException.class); exception.expectMessage("Exception type cannot be null"); when(mock.isEmpty()).thenThrow(RuntimeException.class, (Class[]) null); } @Test public void shouldNotAllowSettingNullVarArgThrowableClass() { exception.expect(MockitoException.class); exception.expectMessage("Exception type cannot be null"); when(mock.isEmpty()).thenThrow(RuntimeException.class, (Class) null); } @Test public void doThrowShouldNotAllowSettingNullThrowableClass() { exception.expect(MockitoException.class); exception.expectMessage("Exception type cannot be null"); doThrow((Class) null).when(mock).isEmpty(); } @Test public void doThrowShouldNotAllowSettingNullThrowableClasses() throws Exception { exception.expect(MockitoException.class); exception.expectMessage("Exception type cannot be null"); doThrow(RuntimeException.class, (Class) null).when(mock).isEmpty(); } @Test public void doThrowShouldNotAllowSettingNullVarArgThrowableClasses() throws Exception { exception.expect(MockitoException.class); exception.expectMessage("Exception type cannot be null"); doThrow(RuntimeException.class, (Class[]) null).when(mock).isEmpty(); } @Test public void shouldNotAllowSettingNullVarArgsThrowableClasses() throws Exception { exception.expect(MockitoException.class); exception.expectMessage("Exception type cannot be null"); when(mock.isEmpty()).thenThrow(RuntimeException.class, (Class[]) null); } @Test public void shouldNotAllowDifferntCheckedException() throws Exception { IMethods mock = mock(IMethods.class); exception.expect(MockitoException.class); exception.expectMessage("Checked exception is invalid for this method"); when(mock.throwsIOException(0)).thenThrow(CheckedException.class); } @Test public void shouldNotAllowCheckedExceptionWhenErrorIsDeclared() throws Exception { IMethods mock = mock(IMethods.class); exception.expect(MockitoException.class); exception.expectMessage("Checked exception is invalid for this method"); when(mock.throwsError(0)).thenThrow(CheckedException.class); } @Test public void shouldNotAllowCheckedExceptionWhenNothingIsDeclared() throws Exception { IMethods mock = mock(IMethods.class); exception.expect(MockitoException.class); exception.expectMessage("Checked exception is invalid for this method"); when(mock.throwsNothing(true)).thenThrow(CheckedException.class); } @Test public void shouldMixThrowablesAndReturnsOnDifferentMocks() throws Exception { when(mock.add("ExceptionOne")).thenThrow(new ExceptionOne()); when(mock.getLast()).thenReturn("last"); doThrow(new ExceptionTwo()).when(mock).clear(); doThrow(new ExceptionThree()).when(mockTwo).clear(); when(mockTwo.containsValue("ExceptionFour")).thenThrow(new ExceptionFour()); when(mockTwo.get("Are you there?")).thenReturn("Yes!"); assertNull(mockTwo.get("foo")); assertTrue(mockTwo.keySet().isEmpty()); assertEquals("Yes!", mockTwo.get("Are you there?")); try { mockTwo.clear(); fail(); } catch (ExceptionThree e) { } try { mockTwo.containsValue("ExceptionFour"); fail(); } catch (ExceptionFour e) { } assertNull(mock.getFirst()); assertEquals("last", mock.getLast()); try { mock.add("ExceptionOne"); fail(); } catch (ExceptionOne e) { } try { mock.clear(); fail(); } catch (ExceptionTwo e) { } } @Test public void shouldStubbingWithThrowableBeVerifiable() { when(mock.size()).thenThrow(new RuntimeException()); doThrow(new RuntimeException()).when(mock).clone(); try { mock.size(); fail(); } catch (RuntimeException e) { } try { mock.clone(); fail(); } catch (RuntimeException e) { } verify(mock).size(); verify(mock).clone(); verifyNoMoreInteractions(mock); } @Test public void shouldStubbingWithThrowableFailVerification() { when(mock.size()).thenThrow(new RuntimeException()); doThrow(new RuntimeException()).when(mock).clone(); verifyZeroInteractions(mock); mock.add("test"); try { verify(mock).size(); fail(); } catch (WantedButNotInvoked e) { } try { verify(mock).clone(); fail(); } catch (WantedButNotInvoked e) { } try { verifyNoMoreInteractions(mock); fail(); } catch (NoInteractionsWanted e) { } } private class ExceptionOne extends RuntimeException { } private class ExceptionTwo extends RuntimeException { } private class ExceptionThree extends RuntimeException { } private class ExceptionFour extends RuntimeException { } private class CheckedException extends Exception { } public class NaughtyException extends RuntimeException { public NaughtyException() { throw new RuntimeException("boo!"); } } }