Repository: mockito/mockito
Issue: Mockito remains in unfinished stubbing state if a stubbing fails
Labels: bug

If one of `doThrow` instructions failed due to InstantiationError, Mockito remains in "unfinished stubbing" state and can no longer mock anything.

I had this issue in a single JUnit 4 test, but the fact that Mockito remained in "unfinished stubbing" state used to result in _all_ tests being marked as failed (I couldn't reproduce the last effect with the latest Mockito neither in JUnit 4 nor with JUnit 5 now, so the issue is applicable to a single test invocation only).

```java
import java.util.List;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import org.mockito.Mockito;

class UninstantiableTest {

  @RepeatedTest(2)
  void tryThrow01(RepetitionInfo i) {
    if (i.getCurrentRepetition() == 1) {
      // Stub using uninstantiable exception.
      try {
        List mock = Mockito.mock(List.class);

        Mockito.doThrow(UninstantiableException.class).when(mock).clear();
      } catch (InstantiationError expected) {
        // Get a j.l.InstantiationError.
      }
    }

    // Try to stub another mock, this time using a valid exception type.
    {
      List mock = Mockito.mock(List.class);

      // The following operation results in "UnfinishedStubbing"
      Mockito.doThrow(RuntimeException.class).when(mock).clear();
    }
  }

  abstract static class UninstantiableException extends RuntimeException {}
}
```

Mockito version 2.23.0


check that

 - [x] The mockito message in the stacktrace have useful information, but it didn't help
 - [x] The problematic code (if that's possible) is copied here;
       Note that some configuration are impossible to mock via Mockito
 - [x] Provide versions (mockito / jdk / os / any other relevant information)
 - [x] Provide a [Short, Self Contained, Correct (Compilable), Example](http://sscce.org) of the issue
       (same as any question on stackoverflow.com)
 - [x] Read the [contributing guide](https://github.com/mockito/mockito/blob/master/.github/CONTRIBUTING.md)




Issue comments:
A fix (if this **is** an issue) might be simple:

```
Index: src/main/java/org/mockito/internal/stubbing/StubberImpl.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/main/java/org/mockito/internal/stubbing/StubberImpl.java	(revision 11e28796ecd89470ca50632e0fe9b2e4260e323a)
+++ src/main/java/org/mockito/internal/stubbing/StubberImpl.java	(date 1532965613000)
@@ -93,6 +93,9 @@
         } catch (RuntimeException instantiationError) {
             mockingProgress().reset();
             throw instantiationError;
+        } catch (InstantiationError instantiationError) {
+            mockingProgress().reset();
+            throw instantiationError;
         }
         return doThrow(e);
     }
```
@dmitry-timofeev, do you want to take a stab at it? Please provide top level test that demonstrates the problem, too. It would be really helpful. Thank you!
Hi @mockitoguy , thank you for having a look. I'm a little busy at work, therefore I won't be able to in the coming weeks.
That's fair, we will try find time to work on this. Thank you for reporting!

Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/org/mockito/internal/stubbing/StubberImpl.java b/src/main/java/org/mockito/internal/stubbing/StubberImpl.java
index 2172809e36..42795a723b 100644
--- a/src/main/java/org/mockito/internal/stubbing/StubberImpl.java
+++ b/src/main/java/org/mockito/internal/stubbing/StubberImpl.java
@@ -87,12 +87,16 @@ public Stubber doThrow(Class<? extends Throwable> toBeThrown) {
             mockingProgress().reset();
             throw notAnException();
         }
-        Throwable e;
+        Throwable e = null;
         try {
             e = newInstance(toBeThrown);
-        } catch (RuntimeException instantiationError) {
-            mockingProgress().reset();
-            throw instantiationError;
+        } finally {
+            if (e == null) {
+                //this means that an exception or error was thrown when trying to create new instance
+                //we don't want 'catch' statement here because we want the exception to be thrown to the user
+                //however, we do want to clean up state (e.g. "stubbing started").
+                mockingProgress().reset();
+            }
         }
         return doThrow(e);
     }


Test patch:
diff --git a/src/test/java/org/mockitousage/stubbing/StubbingWithBadThrowablesTest.java b/src/test/java/org/mockitousage/stubbing/StubbingWithBadThrowablesTest.java
new file mode 100644
index 0000000000..b0c29d5bee
--- /dev/null
+++ b/src/test/java/org/mockitousage/stubbing/StubbingWithBadThrowablesTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitousage.stubbing;
+
+import org.assertj.core.api.Assertions;
+import org.assertj.core.api.ThrowableAssert;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockitoutil.TestBase;
+
+import java.util.List;
+
+import static org.mockito.Mockito.doThrow;
+
+//issue 1514
+@SuppressWarnings({ "serial", "unchecked", "rawtypes" })
+public class StubbingWithBadThrowablesTest extends TestBase {
+
+    @Mock List mock;
+
+    @Test
+    public void handles_bad_exception() {
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            public void call() {
+                doThrow(UninstantiableException.class).when(mock).clear();
+            }
+        }).isInstanceOf(InstantiationError.class); //because the exception cannot be instantiated
+
+        //ensure that the state is cleaned
+        Mockito.validateMockitoUsage();
+    }
+
+    abstract static class UninstantiableException extends RuntimeException {}
+}
diff --git a/subprojects/junit-jupiter/src/test/java/org/mockitousage/UninstantiableThrowableTest.java b/subprojects/junit-jupiter/src/test/java/org/mockitousage/UninstantiableThrowableTest.java
new file mode 100644
index 0000000000..2ef3128016
--- /dev/null
+++ b/subprojects/junit-jupiter/src/test/java/org/mockitousage/UninstantiableThrowableTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitousage;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.RepeatedTest;
+import org.junit.jupiter.api.RepetitionInfo;
+import org.mockito.Mockito;
+
+import java.util.List;
+
+//issue 1514
+class UninstantiableThrowableTest {
+
+    @RepeatedTest(2)
+    void should_behave_consistently(RepetitionInfo i) {
+        List mock = Mockito.mock(List.class);
+        if (i.getCurrentRepetition() == 1) {
+            Assertions.assertThatThrownBy(
+                () -> Mockito.doThrow(UninstantiableException.class).when(mock).clear())
+                .isInstanceOf(InstantiationError.class);
+        }
+
+        // The following operation results in "UnfinishedStubbing"
+        Mockito.doThrow(RuntimeException.class).when(mock).clear();
+    }
+
+    abstract static class UninstantiableException extends RuntimeException { }
+}