org.mockito.internal.stubbing.answers.InvocationInfo#isValidException is doing validation on the exception types that can be thrown from this method.
In my codebase, I'm programming against an interface, but in fact, a spy is created from an instance that is implementing the interface, that drops the exception types that that implementation does not throw. However, the code that is calling the interface is of course unaware of that fact. Also, that implementation is a mock implementation (a real mock implementation, not a Mockito mock()/spy() instance).
A testcase here:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.exceptions.base.MockitoException;
import org.mockito.junit.jupiter.MockitoExtension;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy;
@ExtendWith(MockitoExtension.class)
public class MockitoExceptionTypesIssue {
@Test
void exceptionTypeIoExceptionShouldBeMockableForObjectBeingSpyedOn() {
final I x = spy(new C());
final IOException ioException = new IOException("Oh my god!");
final MockitoException e = assertThrows(
MockitoException.class,
() -> doThrow(ioException)
.when(x)
.m());
assertEquals("\n" +
"Checked exception is invalid for this method!\n" +
"Invalid: " + ioException,
e.getMessage()
);
}
interface I {
void m() throws IOException;
}
static class C implements I {
public void m() {
// no-op
}
}
}
org.mockito.internal.stubbing.answers.InvocationInfo#isValidException is doing validation on the exception types that can be thrown from this method.
In my codebase, I'm programming against an interface, but in fact, a spy is created from an instance that is implementing the interface, that drops the exception types that that implementation does not throw. However, the code that is calling the interface is of course unaware of that fact. Also, that implementation is a mock implementation (a real mock implementation, not a Mockito mock()/spy() instance).
A testcase here: