Merge pie-platform-release to aosp-master - DO NOT MERGE

Change-Id: Ic796c6fd3d623125ba29410ee5c23ceb2e586712
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 98b50ee..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-# IntelliJ IDEA
-.idea/
-*.iml
diff --git a/Android.bp b/Android.bp
index 22e8cbf..a82e8f6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -44,8 +44,14 @@
             ],
         },
     },
-    sdk_version: "16",
+    sdk_version: "core_current",
     java_version: "1.7",
+
+    errorprone: {
+        javacflags: [
+            "-Xep:CollectionIncompatibleType:WARN",  // b/74213384
+        ],
+    }
 }
 
 // Compatibility library for old name of host target
@@ -60,7 +66,7 @@
     hostdex: true,
     no_framework_libs: true,
     static_libs: ["mockito"],
-    sdk_version: "16",
+    sdk_version: "core_current",
 }
 
 // Compatibility library for old name of host target
@@ -70,75 +76,15 @@
     java_resource_dirs: ["subprojects/inline/src/main/resources"],
 }
 
-// Main target for dependent projects. Bundles all the run-time dependencies
-// needed to run Mockito tests on the device.
-java_library_static {
-    name: "mockito-target",
-    no_framework_libs: true,
-    static_libs: [
-        "mockito-target-minus-junit4",
-        "junit",
-    ],
-    sdk_version: "16",
-}
-
-// A mockito target that doesn't pull in junit. This is used to work around
-// issues caused by multiple copies of junit in the classpath, usually when a test
-// using mockito is run using android.test.runner.
-java_library_static {
-    name: "mockito-target-minus-junit4",
-    no_framework_libs: true,
-    static_libs: [
-        "mockito",
-        "dexmaker",
-        "dexmaker-mockmaker",
-        "objenesis",
-    ],
-    libs: ["junit"],
-    sdk_version: "16",
-
-    java_version: "1.7",
-}
-
-// Main target for dependent projects. Bundles all the run-time dependencies
-// needed to run Mockito tests on the device.
-java_library_static {
-    name: "mockito-target-inline",
-    no_framework_libs: true,
-    static_libs: [
-        "mockito-target-inline-minus-junit4",
-        "junit",
-    ],
-    sdk_version: "current",
-}
-
-// A mockito target that doesn't pull in junit. This is used to work around
-// issues caused by multiple copies of junit in the classpath, usually when a test
-// using mockito is run using android.test.runner.
-java_library_static {
-    name: "mockito-target-inline-minus-junit4",
-    no_framework_libs: true,
-    static_libs: [
-        "mockito",
-        "dexmaker",
-        "dexmaker-inline-mockmaker",
-        "objenesis",
-    ],
-    libs: ["junit"],
-    sdk_version: "current",
-
-    java_version: "1.7",
-}
-
 // Host prebuilt dependencies.
 // ============================================================
 java_import_host {
     name: "mockito-byte-buddy",
-    jars: ["lib/byte-buddy-1.7.9.jar"],
+    jars: ["lib/byte-buddy-1.8.15.jar"],
 }
 
 java_import_host {
     name: "mockito-byte-buddy-agent",
-    jars: ["lib/byte-buddy-agent-1.7.9.jar"],
+    jars: ["lib/byte-buddy-agent-1.8.15.jar"],
 }
 
diff --git a/README.version b/README.version
index bbabbe6..35f650c 100644
--- a/README.version
+++ b/README.version
@@ -1,5 +1,5 @@
 URL: https://github.com/mockito/mockito
-Version: v2.16.0
+Version: v2.21.0
 License: Apache 2.0
 Description: Mockito is a mocking framework with a clean and simple API.
 
diff --git a/lib/byte-buddy-1.7.9-sources.jar b/lib/byte-buddy-1.7.9-sources.jar
deleted file mode 100644
index 0dd5b51..0000000
--- a/lib/byte-buddy-1.7.9-sources.jar
+++ /dev/null
Binary files differ
diff --git a/lib/byte-buddy-1.7.9.jar b/lib/byte-buddy-1.7.9.jar
deleted file mode 100644
index a348888..0000000
--- a/lib/byte-buddy-1.7.9.jar
+++ /dev/null
Binary files differ
diff --git a/lib/byte-buddy-1.8.15-sources.jar b/lib/byte-buddy-1.8.15-sources.jar
new file mode 100644
index 0000000..523015e
--- /dev/null
+++ b/lib/byte-buddy-1.8.15-sources.jar
Binary files differ
diff --git a/lib/byte-buddy-1.8.15.jar b/lib/byte-buddy-1.8.15.jar
new file mode 100644
index 0000000..b8c8379
--- /dev/null
+++ b/lib/byte-buddy-1.8.15.jar
Binary files differ
diff --git a/lib/byte-buddy-1.7.9.jar.txt b/lib/byte-buddy-1.8.15.jar.txt
similarity index 100%
rename from lib/byte-buddy-1.7.9.jar.txt
rename to lib/byte-buddy-1.8.15.jar.txt
diff --git a/lib/byte-buddy-agent-1.7.9-sources.jar b/lib/byte-buddy-agent-1.7.9-sources.jar
deleted file mode 100644
index 4940121..0000000
--- a/lib/byte-buddy-agent-1.7.9-sources.jar
+++ /dev/null
Binary files differ
diff --git a/lib/byte-buddy-agent-1.7.9.jar b/lib/byte-buddy-agent-1.7.9.jar
deleted file mode 100644
index 9fcfb59..0000000
--- a/lib/byte-buddy-agent-1.7.9.jar
+++ /dev/null
Binary files differ
diff --git a/lib/byte-buddy-agent-1.7.9.jar.txt b/lib/byte-buddy-agent-1.7.9.jar.txt
deleted file mode 100644
index e06d208..0000000
--- a/lib/byte-buddy-agent-1.7.9.jar.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "{}"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright {yyyy} {name of copyright owner}
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
diff --git a/lib/byte-buddy-agent-1.8.15-sources.jar b/lib/byte-buddy-agent-1.8.15-sources.jar
new file mode 100644
index 0000000..24ab2ee
--- /dev/null
+++ b/lib/byte-buddy-agent-1.8.15-sources.jar
Binary files differ
diff --git a/lib/byte-buddy-agent-1.8.15.jar b/lib/byte-buddy-agent-1.8.15.jar
new file mode 100644
index 0000000..1709e55
--- /dev/null
+++ b/lib/byte-buddy-agent-1.8.15.jar
Binary files differ
diff --git a/lib/byte-buddy-1.7.9.jar.txt b/lib/byte-buddy-agent-1.8.15.jar.txt
similarity index 100%
copy from lib/byte-buddy-1.7.9.jar.txt
copy to lib/byte-buddy-agent-1.8.15.jar.txt
diff --git a/src/main/java/org/mockito/CheckReturnValue.java b/src/main/java/org/mockito/CheckReturnValue.java
index 59bfc33..0498c14 100644
--- a/src/main/java/org/mockito/CheckReturnValue.java
+++ b/src/main/java/org/mockito/CheckReturnValue.java
@@ -28,5 +28,5 @@
     ElementType.TYPE
 })
 @Retention(RetentionPolicy.CLASS)
-@interface CheckReturnValue {
+public @interface CheckReturnValue {
 }
diff --git a/src/main/java/org/mockito/MockSettings.java b/src/main/java/org/mockito/MockSettings.java
index 82dc050..c79c243 100644
--- a/src/main/java/org/mockito/MockSettings.java
+++ b/src/main/java/org/mockito/MockSettings.java
@@ -4,12 +4,15 @@
  */
 package org.mockito;
 
+import org.mockito.exceptions.misusing.PotentialStubbingProblem;
+import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
 import org.mockito.invocation.InvocationFactory;
 import org.mockito.invocation.MockHandler;
 import org.mockito.listeners.InvocationListener;
 import org.mockito.listeners.VerificationStartedListener;
 import org.mockito.mock.MockCreationSettings;
 import org.mockito.mock.SerializableMode;
+import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Answer;
 
 import java.io.Serializable;
@@ -316,4 +319,18 @@
      */
     @Incubating
     <T> MockCreationSettings<T> build(Class<T> typeToMock);
+
+    /**
+     * Lenient mocks bypass "strict stubbing" validation (see {@link Strictness#STRICT_STUBS}).
+     * When mock is declared as lenient none of its stubbings will be checked for potential stubbing problems such as
+     * 'unnecessary stubbing' ({@link UnnecessaryStubbingException}) or for 'stubbing argument mismatch' {@link PotentialStubbingProblem}.
+     *
+     * <pre class="code"><code class="java">
+     *   Foo mock = mock(Foo.class, withSettings.lenient());
+     * </code></pre>
+     *
+     * For more information and an elaborate example, see {@link Mockito#lenient()}.
+     */
+    @Incubating
+    MockSettings lenient();
 }
diff --git a/src/main/java/org/mockito/Mockito.java b/src/main/java/org/mockito/Mockito.java
index b25dae5..2d06e58 100644
--- a/src/main/java/org/mockito/Mockito.java
+++ b/src/main/java/org/mockito/Mockito.java
@@ -4,6 +4,8 @@
  */
 package org.mockito;
 
+import org.mockito.exceptions.misusing.PotentialStubbingProblem;
+import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
 import org.mockito.internal.InternalMockHandler;
 import org.mockito.internal.MockitoCore;
 import org.mockito.internal.creation.MockSettingsImpl;
@@ -28,6 +30,7 @@
 import org.mockito.session.MockitoSessionLogger;
 import org.mockito.stubbing.Answer;
 import org.mockito.stubbing.Answer1;
+import org.mockito.stubbing.LenientStubber;
 import org.mockito.stubbing.OngoingStubbing;
 import org.mockito.stubbing.Stubber;
 import org.mockito.stubbing.Stubbing;
@@ -94,11 +97,13 @@
  *      <a href="#37">37. Java 8 Custom Answer Support (Since 2.1.0)</a><br/>
  *      <a href="#38">38. Meta data and generic type retention (Since 2.1.0)</a><br/>
  *      <a href="#39">39. Mocking final types, enums and final methods (Since 2.1.0)</a><br/>
- *      <a href="#40">40. (*new*) Improved productivity and cleaner tests with "stricter" Mockito (Since 2.+)</a><br/>
- *      <a href="#41">41. (**new**) Advanced public API for framework integrations (Since 2.10.+)</a><br/>
- *      <a href="#42">42. (**new**) New API for integrations: listening on verification start events (Since 2.11.+)</a><br/>
- *      <a href="#43">43. (**new**) New API for integrations: <code>MockitoSession</code> is usable by testing frameworks (Since 2.15.+)</a><br/>
+ *      <a href="#40">40. Improved productivity and cleaner tests with "stricter" Mockito (Since 2.+)</a><br/>
+ *      <a href="#41">41. Advanced public API for framework integrations (Since 2.10.+)</a><br/>
+ *      <a href="#42">42. New API for integrations: listening on verification start events (Since 2.11.+)</a><br/>
+ *      <a href="#43">43. New API for integrations: <code>MockitoSession</code> is usable by testing frameworks (Since 2.15.+)</a><br/>
  *      <a href="#44">44. Deprecated <code>org.mockito.plugins.InstantiatorProvider</code> as it was leaking internal API. it was replaced by <code>org.mockito.plugins.InstantiatorProvider2 (Since 2.15.4)</code></a><br/>
+ *      <a href="#45">45. New JUnit Jupiter (JUnit5+) extension</a><br/>
+ *      <a href="#46">46. New <code>Mockito.lenient()</code> and <code>MockSettings.lenient()</code> methods (Since 2.20.0</a><br/>
  * </b>
  *
  * <h3 id="0">0. <a class="meaningful_link" href="#mockito2" name="mockito2">Migrating to Mockito 2</a></h3>
@@ -111,7 +116,7 @@
  * see '<a href="https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2">What's new in Mockito 2</a>' wiki page.
  * We hope that you enjoy Mockito 2!
  *
- * <h3 id="0.1">0.1. <a class="meaningful_link" href="#mockito" name="mockito-android">Mockito Android support</a></h3>
+ * <h3 id="0.1">0.1. <a class="meaningful_link" href="#mockito-android" name="mockito-android">Mockito Android support</a></h3>
  *
  * With Mockito version 2.6.1 we ship "native" Android support. To enable Android support, add the `mockito-android` library as dependency
  * to your project. This artifact is published to the same Mockito organization and can be imported for Android as follows:
@@ -521,15 +526,16 @@
  * any clean & simple code. However, if you do have a need to stub with the generic Answer interface, here is an example:
  *
  * <pre class="code"><code class="java">
- * when(mock.someMethod(anyString())).thenAnswer(new Answer() {
- *     Object answer(InvocationOnMock invocation) {
- *         Object[] args = invocation.getArguments();
- *         Object mock = invocation.getMock();
- *         return "called with arguments: " + args;
- *     }
+ * when(mock.someMethod(anyString())).thenAnswer(
+ *     new Answer() {
+ *         public Object answer(InvocationOnMock invocation) {
+ *             Object[] args = invocation.getArguments();
+ *             Object mock = invocation.getMock();
+ *             return "called with arguments: " + Arrays.toString(args);
+ *         }
  * });
  *
- * //the following prints "called with arguments: foo"
+ * //Following prints "called with arguments: [foo]"
  * System.out.println(mock.someMethod("foo"));
  * </code></pre>
  *
@@ -878,20 +884,17 @@
  * Examples:
  * <p>
  * <pre class="code"><code class="java">
- *   //passes when someMethod() is called within given time span
+ *   //passes when someMethod() is called no later than within 100 ms
+ *   //exits immediately when verification is satisfied (e.g. may not wait full 100 ms)
  *   verify(mock, timeout(100)).someMethod();
  *   //above is an alias to:
  *   verify(mock, timeout(100).times(1)).someMethod();
  *
- *   //passes when someMethod() is called <b>*exactly*</b> 2 times within given time span
+ *   //passes as soon as someMethod() has been called 2 times under 100 ms
  *   verify(mock, timeout(100).times(2)).someMethod();
  *
- *   //passes when someMethod() is called <b>*at least*</b> 2 times within given time span
+ *   //equivalent: this also passes as soon as someMethod() has been called 2 times under 100 ms
  *   verify(mock, timeout(100).atLeast(2)).someMethod();
- *
- *   //verifies someMethod() within given time span using given verification mode
- *   //useful only if you have your own custom verification modes.
- *   verify(mock, new Timeout(100, yourOwnVerificationMode)).someMethod();
  * </code></pre>
  *
  *
@@ -982,9 +985,9 @@
  *   details.getMockCreationSettings().getTypeToMock();
  *   details.getMockCreationSettings().getDefaultAnswer();
  *
- *   //Getting interactions and stubbings of the mock:
+ *   //Getting invocations and stubbings of the mock:
  *   MockingDetails details = mockingDetails(mock);
- *   details.getInteractions();
+ *   details.getInvocations();
  *   details.getStubbings();
  *
  *   //Printing all interactions (including stubbing, unused stubs)
@@ -1054,7 +1057,7 @@
  * then(person).should(times(2)).ride(bike);
  * </code></pre>
  *
- * For more information and an example see {@link BDDMockito#then(Object)}}
+ * For more information and an example see {@link BDDMockito#then(Object)}
  *
  *
  *
@@ -1166,7 +1169,7 @@
  * More information here {@link org.mockito.plugins.PluginSwitch}.
  *
  *
- * <h3 id="35">35. <a class="meaningful_link" href="#BDD_behavior_verification" name="BDD_behavior_verification">Custom verification failure message</a> (Since 2.1.0)</h3>
+ * <h3 id="35">35. <a class="meaningful_link" href="#Custom_verification_failure_message" name="Custom_verification_failure_message">Custom verification failure message</a> (Since 2.1.0)</h3>
  * <p>
  * Allows specifying a custom message to be printed if verification fails.
  * <p>
@@ -1211,7 +1214,7 @@
  *
  * // this can also be used when defining the behaviour of a mock under different inputs
  * // in this case if the input list was fewer than 3 items the mock returns null
- * when(mock.someMethod(argThat(list -> list.size()<3))).willReturn(null);
+ * when(mock.someMethod(argThat(list -> list.size()<3))).thenReturn(null);
  * </code></pre>
  *
  * <h3 id="37">37. <a class="meaningful_link" href="#Java_8_Custom_Answers" name="Java_8_Custom_Answers">Java 8 Custom Answer Support</a> (Since 2.1.0)</h3>
@@ -1325,10 +1328,6 @@
  * Currently, the feature is still optional as we wait for more feedback from the community.
  *
  * <p>
- * This feature is turned off by default because it is based on completely different mocking mechanism
- * that requires more feedback from the community.
- *
- * <p>
  * This alternative mock maker which uses
  * a combination of both Java instrumentation API and sub-classing rather than creating a new class to represent
  * a mock. This way, it becomes possible to mock final types and methods.
@@ -1371,7 +1370,7 @@
  * <code>org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker</code>
  *
  * <h3 id="40">40. <a class="meaningful_link" href="#strict_mockito" name="strict_mockito">
- *     (*new*) Improved productivity and cleaner tests with "stricter" Mockito</a> (Since 2.+)</h3>
+ *     Improved productivity and cleaner tests with "stricter" Mockito</a> (Since 2.+)</h3>
  *
  * To quickly find out how "stricter" Mockito can make you more productive and get your tests cleaner, see:
  * <ul>
@@ -1399,7 +1398,7 @@
  * <a href="https://github.com/mockito/mockito/issues/769">issue 769</a>.
  *
  * <h3 id="41">41. <a class="meaningful_link" href="#framework_integrations_api" name="framework_integrations_api">
- *      (**new**) Advanced public API for framework integrations (Since 2.10.+)</a></h3>
+ *      Advanced public API for framework integrations (Since 2.10.+)</a></h3>
  *
  * In Summer 2017 we decided that Mockito
  * <a href="https://www.linkedin.com/pulse/mockito-vs-powermock-opinionated-dogmatic-static-mocking-faber">
@@ -1452,7 +1451,7 @@
  * Do you have feedback? Please leave comment in <a href="https://github.com/mockito/mockito/issues/1110">issue 1110</a>.
  *
  * <h3 id="42">42. <a class="meaningful_link" href="#verifiation_started_listener" name="verifiation_started_listener">
- *       (**new**) New API for integrations: listening on verification start events (Since 2.11.+)</a></h3>
+ *       New API for integrations: listening on verification start events (Since 2.11.+)</a></h3>
  *
  * Framework integrations such as <a href="https://projects.spring.io/spring-boot">Spring Boot</a> needs public API to tackle double-proxy use case
  * (<a href="https://github.com/mockito/mockito/issues/1191">issue 1191</a>).
@@ -1472,7 +1471,7 @@
  * </ul>
  *
  * <h3 id="43">43. <a class="meaningful_link" href="#mockito_session_testing_frameworks" name="mockito_session_testing_frameworks">
- *       (**new**) New API for integrations: <code>MockitoSession</code> is usable by testing frameworks (Since 2.15.+)</a></h3>
+ *       New API for integrations: <code>MockitoSession</code> is usable by testing frameworks (Since 2.15.+)</a></h3>
  *
  * <p>{@link MockitoSessionBuilder} and {@link MockitoSession} were enhanced to enable reuse by testing framework
  * integrations (e.g. {@link MockitoRule} for JUnit):</p>
@@ -1506,6 +1505,33 @@
  * <p>{@link org.mockito.plugins.InstantiatorProvider} returned an internal API. Hence it was deprecated and replaced
  * by {@link org.mockito.plugins.InstantiatorProvider2}. Old {@link org.mockito.plugins.InstantiatorProvider
  * instantiator providers} will continue to work, but it is recommended to switch to the new API.</p>
+ *
+ * <h3 id="45">45. <a class="meaningful_link" href="#junit5_mockito" name="junit5_mockito">New JUnit Jupiter (JUnit5+) extension</a></h3>
+ *
+ * For integration with JUnit Jupiter (JUnit5+), use the `org.mockito:mockito-junit-jupiter` artifact.
+ * For more information about the usage of the integration, see <a href="http://javadoc.io/page/org.mockito/mockito-junit-jupiter/latest/org/mockito/junit/jupiter/MockitoExtension.html">the JavaDoc of <code>MockitoExtension</code></a>.
+ *
+ * <h3 id="46">46. <a class="meaningful_link" href="#mockito_lenient" name="mockito_lenient">
+ *       New <code>Mockito.lenient()</code> and <code>MockSettings.lenient()</code> methods (Since 2.20.0)</a></h3>
+ *
+ * Strict stubbing feature is available since early Mockito 2.
+ * It is very useful because it drives cleaner tests and improved productivity.
+ * Strict stubbing reports unnecessary stubs, detects stubbing argument mismatch and makes the tests more DRY ({@link Strictness#STRICT_STUBS}).
+ * This comes with a trade-off: in some cases, you may get false negatives from strict stubbing.
+ * To remedy those scenarios you can now configure specific stubbing to be lenient, while all the other stubbings and mocks use strict stubbing:
+ *
+ * <pre class="code"><code class="java">
+ *   lenient().when(mock.foo()).thenReturn("ok");
+ * </code></pre>
+ *
+ * If you want all the stubbings on a given mock to be lenient, you can configure the mock accordingly:
+ *
+ * <pre class="code"><code class="java">
+ *   Foo mock = Mockito.mock(Foo.class, withSettings().lenient());
+ * </code></pre>
+ *
+ * For more information refer to {@link Mockito#lenient()}.
+ * Let us know how do you find the new feature by opening a GitHub issue to discuss!
  */
 @SuppressWarnings("unchecked")
 public class Mockito extends ArgumentMatchers {
@@ -1773,6 +1799,7 @@
      * @param classToMock class or interface to mock
      * @return mock object
      */
+    @CheckReturnValue
     public static <T> T mock(Class<T> classToMock) {
         return mock(classToMock, withSettings());
     }
@@ -1792,6 +1819,7 @@
      * @param name of the mock
      * @return mock object
      */
+    @CheckReturnValue
     public static <T> T mock(Class<T> classToMock, String name) {
         return mock(classToMock, withSettings()
                 .name(name)
@@ -1810,6 +1838,7 @@
      * @return A {@link org.mockito.MockingDetails} instance.
      * @since 1.9.5
      */
+    @CheckReturnValue
     public static MockingDetails mockingDetails(Object toInspect) {
         return MOCKITO_CORE.mockingDetails(toInspect);
     }
@@ -1833,6 +1862,7 @@
      *
      * @return mock object
      */
+    @CheckReturnValue
     public static <T> T mock(Class<T> classToMock, Answer defaultAnswer) {
         return mock(classToMock, withSettings().defaultAnswer(defaultAnswer));
     }
@@ -1860,6 +1890,7 @@
      * @param mockSettings additional mock settings
      * @return mock object
      */
+    @CheckReturnValue
     public static <T> T mock(Class<T> classToMock, MockSettings mockSettings) {
         return MOCKITO_CORE.mock(classToMock, mockSettings);
     }
@@ -1943,6 +1974,7 @@
      *            to spy on
      * @return a spy of the real object
      */
+    @CheckReturnValue
     public static <T> T spy(T object) {
         return MOCKITO_CORE.mock((Class<T>) object.getClass(), withSettings()
                 .spiedInstance(object)
@@ -1977,6 +2009,7 @@
      * @since 1.10.12
      */
     @Incubating
+    @CheckReturnValue
     public static <T> T spy(Class<T> classToSpy) {
         return MOCKITO_CORE.mock(classToSpy, withSettings()
                 .useConstructor()
@@ -2521,13 +2554,17 @@
      *
      * @return InOrder object to be used to verify in order
      */
+    @CheckReturnValue
     public static InOrder inOrder(Object... mocks) {
         return MOCKITO_CORE.inOrder(mocks);
     }
 
     /**
      * Ignores stubbed methods of given mocks for the sake of verification.
-     * Sometimes useful when coupled with <code>verifyNoMoreInteractions()</code> or verification <code>inOrder()</code>.
+     * Please consider using {@link Strictness#STRICT_STUBS} feature which eliminates the need for <code>ignoreStubs()</code>
+     * and provides other benefits.
+     * <p>
+     * <code>ignoreStubs()</code> is sometimes useful when coupled with <code>verifyNoMoreInteractions()</code> or verification <code>inOrder()</code>.
      * Helps avoiding redundant verification of stubbed calls - typically we're not interested in verifying stubs.
      * <p>
      * <b>Warning</b>, <code>ignoreStubs()</code> might lead to overuse of <code>verifyNoMoreInteractions(ignoreStubs(...));</code>
@@ -2572,17 +2609,31 @@
      * Ignoring stubs can be used with <b>verification in order</b>:
      * <pre class="code"><code class="java">
      *  List list = mock(List.class);
-     *  when(mock.get(0)).thenReturn("foo");
+     *  when(list.get(0)).thenReturn("foo");
      *
      *  list.add(0);
-     *  System.out.println(list.get(0)); //we don't want to verify this
      *  list.clear();
+     *  System.out.println(list.get(0)); //we don't want to verify this
      *
      *  InOrder inOrder = inOrder(ignoreStubs(list));
      *  inOrder.verify(list).add(0);
      *  inOrder.verify(list).clear();
      *  inOrder.verifyNoMoreInteractions();
      * </code></pre>
+     * Stubbed invocations are automatically verified with {@link Strictness#STRICT_STUBS} feature
+     * and it eliminates the need for <code>ignoreStubs()</code>. Example below uses JUnit Rules:
+     * <pre class="code"><code class="java">
+     *  &#064;Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+     *
+     *  List list = mock(List.class);
+     *  when(list.get(0)).thenReturn("foo");
+     *
+     *  list.size();
+     *  verify(list).size();
+     *
+     *  list.get(0); // Automatically verified by STRICT_STUBS
+     *  verifyNoMoreInteractions(list); // No need of ignoreStubs()
+     * </code></pre>
      *
      * @since 1.9.0
      * @param mocks input mocks that will be changed
@@ -2604,6 +2655,7 @@
      *
      * @return verification mode
      */
+    @CheckReturnValue
     public static VerificationMode times(int wantedNumberOfInvocations) {
         return VerificationModeFactory.times(wantedNumberOfInvocations);
     }
@@ -2625,6 +2677,7 @@
      *
      * @return verification mode
      */
+    @CheckReturnValue
     public static VerificationMode never() {
         return times(0);
     }
@@ -2640,6 +2693,7 @@
      *
      * @return verification mode
      */
+    @CheckReturnValue
     public static VerificationMode atLeastOnce() {
         return VerificationModeFactory.atLeastOnce();
     }
@@ -2656,6 +2710,7 @@
      *
      * @return verification mode
      */
+    @CheckReturnValue
     public static VerificationMode atLeast(int minNumberOfInvocations) {
         return VerificationModeFactory.atLeast(minNumberOfInvocations);
     }
@@ -2672,6 +2727,7 @@
      *
      * @return verification mode
      */
+    @CheckReturnValue
     public static VerificationMode atMost(int maxNumberOfInvocations) {
         return VerificationModeFactory.atMost(maxNumberOfInvocations);
     }
@@ -2689,6 +2745,7 @@
      * @param wantedNumberOfInvocations number of invocations to verify
      * @return  verification mode
      */
+    @CheckReturnValue
     public static VerificationMode calls( int wantedNumberOfInvocations ){
         return VerificationModeFactory.calls( wantedNumberOfInvocations );
     }
@@ -2709,72 +2766,65 @@
      *
      * @return verification mode
      */
+    @CheckReturnValue
     public static VerificationMode only() {
         return VerificationModeFactory.only();
     }
 
     /**
-     * Allows verifying with timeout. It causes a verify to wait for a specified period of time for a desired
-     * interaction rather than fails immediately if has not already happened. May be useful for testing in concurrent
-     * conditions.
+     * Verification will be triggered after given amount of millis, allowing testing of async code.
+     * Useful when interactions with the mock object did not happened yet.
+     * Extensive use of after() method can be a code smell - there are better ways of testing concurrent code.
      * <p>
-     * This differs from {@link Mockito#after after()} in that after() will wait the full period, unless
-     * the final test result is known early (e.g. if a never() fails), whereas timeout() will stop early as soon
-     * as verification passes, producing different behaviour when used with times(2), for example, which can pass
-     * and then later fail. In that case, timeout would pass as soon as times(2) passes, whereas after would run until
-     * times(2) failed, and then fail.
+     * See also {@link #after(long)} method for testing async code.
+     * Differences between {@code timeout()} and {@code after} are explained in Javadoc for {@link #after(long)}.
      * <p>
-     * This feature should be used rarely - figure out a better way of testing your multi-threaded system.
+     * Extensive use of {@code timeout()} method can be a code smell - there are better ways of testing concurrent code.
      * <pre class="code"><code class="java">
-     *   //passes when someMethod() is called within given time span
+     *   //passes when someMethod() is called no later than within 100 ms
+     *   //exits immediately when verification is satisfied (e.g. may not wait full 100 ms)
      *   verify(mock, timeout(100)).someMethod();
      *   //above is an alias to:
      *   verify(mock, timeout(100).times(1)).someMethod();
      *
-     *   //passes as soon as someMethod() has been called 2 times before the given timeout
+     *   //passes as soon as someMethod() has been called 2 times under 100 ms
      *   verify(mock, timeout(100).times(2)).someMethod();
      *
-     *   //equivalent: this also passes as soon as someMethod() has been called 2 times before the given timeout
+     *   //equivalent: this also passes as soon as someMethod() has been called 2 times under 100 ms
      *   verify(mock, timeout(100).atLeast(2)).someMethod();
-     *
-     *   //verifies someMethod() within given time span using given verification mode
-     *   //useful only if you have your own custom verification modes.
-     *   verify(mock, new Timeout(100, yourOwnVerificationMode)).someMethod();
      * </code></pre>
      *
      * See examples in javadoc for {@link Mockito} class
      *
-     * @param millis - time span in milliseconds
+     * @param millis - duration in milliseconds
      *
-     * @return verification mode
+     * @return object that allows fluent specification of the verification (times(x), atLeast(y), etc.)
      */
+    @CheckReturnValue
     public static VerificationWithTimeout timeout(long millis) {
         return new Timeout(millis, VerificationModeFactory.times(1));
     }
 
     /**
-     * Allows verifying over a given period. It causes a verify to wait for a specified period of time for a desired
-     * interaction rather than failing immediately if has not already happened. May be useful for testing in concurrent
-     * conditions.
-     * <p>
-     * This differs from {@link Mockito#timeout timeout()} in that after() will wait the full period, whereas timeout()
-     * will stop early as soon as verification passes, producing different behaviour when used with times(2), for example,
-     * which can pass and then later fail. In that case, timeout would pass as soon as times(2) passes, whereas after would
-     * run the full time, which point it will fail, as times(2) has failed.
-     * <p>
-     * This feature should be used rarely - figure out a better way of testing your multi-threaded system.
+     * Verification will be triggered after given amount of millis, allowing testing of async code.
+     * Useful when interactions with the mock object did not happened yet.
+     * Extensive use of after() method can be a code smell - there are better ways of testing concurrent code.
      * <p>
      * Not yet implemented to work with InOrder verification.
+     * <p>
+     * See also {@link #timeout(long)} method for testing async code.
+     * Differences between {@code timeout()} and {@code after()} are explained below.
+     *
      * <pre class="code"><code class="java">
      *   //passes after 100ms, if someMethod() has only been called once at that time.
      *   verify(mock, after(100)).someMethod();
      *   //above is an alias to:
      *   verify(mock, after(100).times(1)).someMethod();
      *
-     *   //passes if someMethod() is called <b>*exactly*</b> 2 times after the given timespan
+     *   //passes if someMethod() is called <b>*exactly*</b> 2 times, as tested after 100 millis
      *   verify(mock, after(100).times(2)).someMethod();
      *
-     *   //passes if someMethod() has not been called after the given timespan
+     *   //passes if someMethod() has not been called, as tested after 100 millis
      *   verify(mock, after(100).never()).someMethod();
      *
      *   //verifies someMethod() after a given time span using given verification mode
@@ -2782,12 +2832,31 @@
      *   verify(mock, new After(100, yourOwnVerificationMode)).someMethod();
      * </code></pre>
      *
+     * <strong>timeout() vs. after()</strong>
+     * <ul>
+     *     <li>timeout() exits immediately with success when verification passes</li>
+     *     <li>after() awaits full duration to check if verification passes</li>
+     * </ul>
+     * Examples:
+     * <pre class="code"><code class="java">
+     *   //1.
+     *   mock.foo();
+     *   verify(mock, after(1000)).foo();
+     *   //waits 1000 millis and succeeds
+     *
+     *   //2.
+     *   mock.foo();
+     *   verify(mock, timeout(1000)).foo();
+     *   //succeeds immediately
+     * </code></pre>
+     *
      * See examples in javadoc for {@link Mockito} class
      *
-     * @param millis - time span in milliseconds
+     * @param millis - duration in milliseconds
      *
-     * @return verification mode
+     * @return object that allows fluent specification of the verification
      */
+    @CheckReturnValue
     public static VerificationAfterDelay after(long millis) {
         return new After(millis, VerificationModeFactory.times(1));
     }
@@ -2871,6 +2940,7 @@
      *
      * @return mock settings instance with defaults.
      */
+    @CheckReturnValue
     public static MockSettings withSettings() {
         return new MockSettingsImpl().defaultAnswer(RETURNS_DEFAULTS);
     }
@@ -2884,6 +2954,7 @@
      * @return verification mode
      * @since 2.1.0
      */
+    @CheckReturnValue
     public static VerificationMode description(String description) {
         return times(1).description(description);
     }
@@ -2893,6 +2964,7 @@
      * An instance of {@code MockingDetails} can be retrieved via {@link #mockingDetails(Object)}.
      */
     @Deprecated
+    @CheckReturnValue
     static MockitoDebugger debug() {
         return new MockitoDebuggerImpl();
     }
@@ -2903,6 +2975,7 @@
      * @since 2.1.0
      */
     @Incubating
+    @CheckReturnValue
     public static MockitoFramework framework() {
         return new DefaultMockitoFramework();
     }
@@ -2916,7 +2989,76 @@
      * @since 2.7.0
      */
     @Incubating
+    @CheckReturnValue
     public static MockitoSessionBuilder mockitoSession() {
         return new DefaultMockitoSessionBuilder();
     }
+
+    /**
+     * Lenient stubs bypass "strict stubbing" validation (see {@link Strictness#STRICT_STUBS}).
+     * When stubbing is declared as lenient, it will not be checked for potential stubbing problems such as
+     * 'unnecessary stubbing' ({@link UnnecessaryStubbingException}) or for 'stubbing argument mismatch' {@link PotentialStubbingProblem}.
+     *
+     * <pre class="code"><code class="java">
+     *   lenient().when(mock.foo()).thenReturn("ok");
+     * </code></pre>
+     *
+     * Most mocks in most tests don't need leniency and should happily prosper with {@link Strictness#STRICT_STUBS}.
+     * <ul>
+     *     <li>If a specific stubbing needs to be lenient - use this method</li>
+     *     <li>If a specific mock need to have stubbings lenient - use {@link MockSettings#lenient()}</li>
+     *     <li>If a specific test method / test class needs to have all stubbings lenient
+     *          - configure strictness using our JUnit support ({@link MockitoJUnit} or Mockito Session ({@link MockitoSession})</li>
+     *
+     * <h3>Elaborate example</h3>
+     *
+     * In below example, 'foo.foo()' is a stubbing that was moved to 'before()' method to avoid duplication.
+     * Doing so makes one of the test methods ('test3()') fail with 'unnecessary stubbing'.
+     * To resolve it we can configure 'foo.foo()' stubbing in 'before()' method to be lenient.
+     * Alternatively, we can configure entire 'foo' mock as lenient.
+     * <p>
+     * This example is simplified and not realistic.
+     * Pushing stubbings to 'before()' method may cause tests to be less readable.
+     * Some repetition in tests is OK, use your own judgement to write great tests!
+     * It is not desired to eliminate all possible duplication from the test code
+     * because it may add complexity and conceal important test information.
+     *
+     * <pre class="code"><code class="java">
+     * public class SomeTest {
+     *
+     *     &#064;Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(STRICT_STUBS);
+     *
+     *     &#064;Mock Foo foo;
+     *     &#064;Mock Bar bar;
+     *
+     *     &#064;Before public void before() {
+     *         when(foo.foo()).thenReturn("ok");
+     *
+     *         // it is better to configure the stubbing to be lenient:
+     *         // lenient().when(foo.foo()).thenReturn("ok");
+     *
+     *         // or the entire mock to be lenient:
+     *         // foo = mock(Foo.class, withSettings().lenient());
+     *     }
+     *
+     *     &#064;Test public void test1() {
+     *         foo.foo();
+     *     }
+     *
+     *     &#064;Test public void test2() {
+     *         foo.foo();
+     *     }
+     *
+     *     &#064;Test public void test3() {
+     *         bar.bar();
+     *     }
+     * }
+     * </code></pre>
+     *
+     * @since 2.20.0
+     */
+    @Incubating
+    public static LenientStubber lenient() {
+        return MOCKITO_CORE.lenient();
+    }
 }
diff --git a/src/main/java/org/mockito/codegen/InjectionBase.java b/src/main/java/org/mockito/codegen/InjectionBase.java
new file mode 100644
index 0000000..b582c3b
--- /dev/null
+++ b/src/main/java/org/mockito/codegen/InjectionBase.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.codegen;
+
+/**
+ * This class is required to resolve a method handle lookup for the {@code org.mockito.codegen} package what requires a preexisting class for the package.
+ * By defining this class, the JVM (starting from Java 9) assures that this package is a part of the Mockito module such that we gain full access rights.
+ */
+public class InjectionBase {
+
+    private InjectionBase() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/src/main/java/org/mockito/exceptions/misusing/PotentialStubbingProblem.java b/src/main/java/org/mockito/exceptions/misusing/PotentialStubbingProblem.java
index 42e990d..5eb6a77 100644
--- a/src/main/java/org/mockito/exceptions/misusing/PotentialStubbingProblem.java
+++ b/src/main/java/org/mockito/exceptions/misusing/PotentialStubbingProblem.java
@@ -5,8 +5,8 @@
 package org.mockito.exceptions.misusing;
 
 import org.mockito.Mockito;
-import org.mockito.quality.Strictness;
 import org.mockito.exceptions.base.MockitoException;
+import org.mockito.quality.Strictness;
 
 /**
  * {@code PotentialStubbingProblem} improves productivity by failing the test early when the user
@@ -53,23 +53,7 @@
  *  It is a well known limitation of Mockito API and another example how Mockito optimizes its clean API for 95% of the cases
  *  while still supporting edge cases.
  *  </li>
- *  <li>Reduce the strictness level in the test method (only for JUnit Rules):
- * <pre class="code"><code class="java">
- * public class ExampleTest {
- *     &#064;Rule
- *     public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
- *
- *     &#064;Test public void exampleTest() {
- *         //Change the strictness level only for this test method:
- *         mockito.strictness(Strictness.LENIENT);
- *
- *         //remaining test code
- *     }
- * }
- * </code></pre>
- *  Currently, reducing strictness is only available to JUnit rules.
- *  If you need it in a different context let us know at <a href="https://github.com/mockito/mockito/issues/857">issue 857</a>.
- *  </li>
+ *  <li>Reduce the strictness level per stubbing, per mock or per test - see {@link Mockito#lenient()}</li>
  *  <li>To opt-out in Mockito 2.x, simply remove the strict stubbing setting in the test class.</li>
  * </ol>
  * <p>
diff --git a/src/main/java/org/mockito/exceptions/misusing/UnnecessaryStubbingException.java b/src/main/java/org/mockito/exceptions/misusing/UnnecessaryStubbingException.java
index c8713b3..2d4605b 100644
--- a/src/main/java/org/mockito/exceptions/misusing/UnnecessaryStubbingException.java
+++ b/src/main/java/org/mockito/exceptions/misusing/UnnecessaryStubbingException.java
@@ -4,23 +4,22 @@
  */
 package org.mockito.exceptions.misusing;
 
+import org.mockito.Mockito;
 import org.mockito.MockitoSession;
 import org.mockito.exceptions.base.MockitoException;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.mockito.junit.MockitoRule;
-import org.mockito.quality.MockitoHint;
-import org.mockito.quality.Strictness;
 
 /**
  * This exception indicates presence of unused stubbings.
  * It is highly recommended to remove unused stubbings to keep the codebase clean.
- * You can opt-out from detecting unused stubbings by configuring:
- * <ul>
- *     <li>JUnit rule - {@link MockitoRule#strictness(Strictness)} or {@link MockitoRule#silent()}</li>
- *     <li>JUnit runner - {@link MockitoJUnitRunner.Silent}</li>
- *     <li>Mockito session - {@link MockitoSession}</li>
- * </ul>
- * For more information about detecting unused stubbings, see {@link MockitoHint}.
+ * In a rare scenario that unused stubbing is a false negative you can opt out from the validation via
+ * (in order of ascending scope):
+ * <ol>
+ *     <li>Declaring specific stubbing as 'lenient' - {@link Mockito#lenient()}</li>
+ *     <li>Declaring specific mock as 'lenient' - {@link org.mockito.MockSettings#lenient()}</li>
+ *     <li>Declaring all mocks in given test class or test method mock as 'lenient' with
+ *          our JUnit support ({@link org.mockito.junit.MockitoJUnit}) or Mockito session ({@link MockitoSession})</li>
+ * </ol>
+ *
  * <p>
  * Unnecessary stubbings are stubbed method calls that were never realized during test execution. Example:
  * <pre class="code"><code class="java">
@@ -45,11 +44,6 @@
  * Mockito JUnit Runner triggers <code>UnnecessaryStubbingException</code> only when none of the test methods use the stubbings.
  * This means that it is ok to put default stubbing in a 'setup' method or in test class constructor.
  * That default stubbing needs to be used at least once by one of the test methods.
- * <p>
- * To find out more about detecting unused stubbings see {@link MockitoHint}.
- * See javadoc for {@link MockitoRule} to understand the behavior or Mockito JUnit Rules.
- * See javadoc for {@link MockitoJUnitRunner} to find out how Mockito JUnit Runner detects unused stubs.
- * See javadoc for {@link MockitoSession} to find out about detecting unused stubs without JUnit.
  */
 public class UnnecessaryStubbingException extends MockitoException {
     public UnnecessaryStubbingException(String message) {
diff --git a/src/main/java/org/mockito/exceptions/verification/MoreThanAllowedActualInvocations.java b/src/main/java/org/mockito/exceptions/verification/MoreThanAllowedActualInvocations.java
new file mode 100644
index 0000000..c3c0ed4
--- /dev/null
+++ b/src/main/java/org/mockito/exceptions/verification/MoreThanAllowedActualInvocations.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito.exceptions.verification;
+
+import org.mockito.exceptions.base.MockitoAssertionError;
+
+/**
+ * Thrown when atMost(x) verification fails. See {@link org.mockito.Mockito#atMost(int)}.
+ *
+ * @since 2.20.5
+ */
+public class MoreThanAllowedActualInvocations extends MockitoAssertionError {
+
+    public MoreThanAllowedActualInvocations(String message) {
+        super(message);
+    }
+}
diff --git a/src/main/java/org/mockito/internal/MockitoCore.java b/src/main/java/org/mockito/internal/MockitoCore.java
index 419d228..68b580a 100644
--- a/src/main/java/org/mockito/internal/MockitoCore.java
+++ b/src/main/java/org/mockito/internal/MockitoCore.java
@@ -12,6 +12,7 @@
 import org.mockito.internal.invocation.finder.VerifiableInvocationsFinder;
 import org.mockito.internal.listeners.VerificationStartedNotifier;
 import org.mockito.internal.progress.MockingProgress;
+import org.mockito.internal.stubbing.DefaultLenientStubber;
 import org.mockito.internal.stubbing.InvocationContainerImpl;
 import org.mockito.internal.stubbing.OngoingStubbingImpl;
 import org.mockito.internal.stubbing.StubberImpl;
@@ -25,6 +26,8 @@
 import org.mockito.invocation.Invocation;
 import org.mockito.invocation.MockHandler;
 import org.mockito.mock.MockCreationSettings;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.LenientStubber;
 import org.mockito.stubbing.OngoingStubbing;
 import org.mockito.stubbing.Stubber;
 import org.mockito.verification.VerificationMode;
@@ -41,6 +44,7 @@
 import static org.mockito.internal.exceptions.Reporter.nullPassedToVerify;
 import static org.mockito.internal.exceptions.Reporter.nullPassedToVerifyNoMoreInteractions;
 import static org.mockito.internal.exceptions.Reporter.nullPassedWhenCreatingInOrder;
+import static org.mockito.internal.exceptions.Reporter.stubPassedToVerify;
 import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
 import static org.mockito.internal.util.MockUtil.createMock;
 import static org.mockito.internal.util.MockUtil.getInvocationContainer;
@@ -88,7 +92,9 @@
             throw notAMockPassedToVerify(mock.getClass());
         }
         MockHandler handler = mockingDetails.getMockHandler();
-
+        if (handler.getMockSettings().isStubOnly()) {
+            throw stubPassedToVerify();
+        }
         mock = (T) VerificationStartedNotifier.notifyVerificationStarted(
             handler.getMockSettings().getVerificationStartedListeners(), mockingDetails);
 
@@ -165,10 +171,14 @@
     }
 
     public Stubber stubber() {
+        return stubber(null);
+    }
+
+    public Stubber stubber(Strictness strictness) {
         MockingProgress mockingProgress = mockingProgress();
         mockingProgress.stubbingStarted();
         mockingProgress.resetOngoingStubbing();
-        return new StubberImpl();
+        return new StubberImpl(strictness);
     }
 
     public void validateMockitoUsage() {
@@ -202,4 +212,8 @@
     public MockingDetails mockingDetails(Object toInspect) {
         return new DefaultMockingDetails(toInspect);
     }
+
+    public LenientStubber lenient() {
+        return new DefaultLenientStubber();
+    }
 }
diff --git a/src/main/java/org/mockito/internal/configuration/MockAnnotationProcessor.java b/src/main/java/org/mockito/internal/configuration/MockAnnotationProcessor.java
index 2f6757d..91086d2 100644
--- a/src/main/java/org/mockito/internal/configuration/MockAnnotationProcessor.java
+++ b/src/main/java/org/mockito/internal/configuration/MockAnnotationProcessor.java
@@ -14,13 +14,18 @@
  * Instantiates a mock on a field annotated by {@link Mock}
  */
 public class MockAnnotationProcessor implements FieldAnnotationProcessor<Mock> {
+    @Override
     public Object process(Mock annotation, Field field) {
+        return processAnnotationForMock(annotation, field.getType(), field.getName());
+    }
+
+    public static Object processAnnotationForMock(Mock annotation, Class<?> type, String name) {
         MockSettings mockSettings = Mockito.withSettings();
         if (annotation.extraInterfaces().length > 0) { // never null
             mockSettings.extraInterfaces(annotation.extraInterfaces());
         }
         if ("".equals(annotation.name())) {
-            mockSettings.name(field.getName());
+            mockSettings.name(name);
         } else {
             mockSettings.name(annotation.name());
         }
@@ -33,6 +38,6 @@
 
         // see @Mock answer default value
         mockSettings.defaultAnswer(annotation.answer());
-        return Mockito.mock(field.getType(), mockSettings);
+        return Mockito.mock(type, mockSettings);
     }
 }
diff --git a/src/main/java/org/mockito/internal/configuration/SpyAnnotationEngine.java b/src/main/java/org/mockito/internal/configuration/SpyAnnotationEngine.java
index a80efbe..92d045d 100644
--- a/src/main/java/org/mockito/internal/configuration/SpyAnnotationEngine.java
+++ b/src/main/java/org/mockito/internal/configuration/SpyAnnotationEngine.java
@@ -140,7 +140,7 @@
         for (Class<? extends Annotation> u : undesiredAnnotations) {
             if (field.isAnnotationPresent(u)) {
                 throw unsupportedCombinationOfAnnotations(annotation.getSimpleName(),
-                                                          annotation.getClass().getSimpleName());
+                                                          u.getSimpleName());
             }
         }
     }
diff --git a/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java b/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java
index 82af98a..ca67730 100644
--- a/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java
+++ b/src/main/java/org/mockito/internal/creation/MockSettingsImpl.java
@@ -226,6 +226,12 @@
         return validatedSettings(typeToMock, (CreationSettings<T>) this);
     }
 
+    @Override
+    public MockSettings lenient() {
+        this.lenient = true;
+        return this;
+    }
+
     private static <T> CreationSettings<T> validatedSettings(Class<T> typeToMock, CreationSettings<T> source) {
         MockCreationValidator validator = new MockCreationValidator();
 
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
index 7d60f6c..64139c2 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineBytecodeGenerator.java
@@ -15,6 +15,7 @@
 import net.bytebuddy.description.method.ParameterDescription;
 import net.bytebuddy.description.type.TypeDescription;
 import net.bytebuddy.dynamic.ClassFileLocator;
+import net.bytebuddy.dynamic.scaffold.MethodGraph;
 import net.bytebuddy.dynamic.scaffold.TypeValidation;
 import net.bytebuddy.implementation.Implementation;
 import net.bytebuddy.jar.asm.ClassVisitor;
@@ -22,6 +23,7 @@
 import net.bytebuddy.jar.asm.Opcodes;
 import net.bytebuddy.matcher.ElementMatchers;
 import net.bytebuddy.pool.TypePool;
+import net.bytebuddy.utility.OpenedClassReader;
 import net.bytebuddy.utility.RandomString;
 import org.mockito.exceptions.base.MockitoException;
 import org.mockito.internal.util.concurrent.WeakConcurrentMap;
@@ -29,7 +31,6 @@
 import org.mockito.mock.SerializableMode;
 
 import java.lang.instrument.ClassFileTransformer;
-import java.lang.instrument.IllegalClassFormatException;
 import java.lang.instrument.Instrumentation;
 import java.lang.reflect.Modifier;
 import java.security.ProtectionDomain;
@@ -44,6 +45,8 @@
 
 public class InlineBytecodeGenerator implements BytecodeGenerator, ClassFileTransformer {
 
+    private static final String PRELOAD = "org.mockito.inline.preload";
+
     @SuppressWarnings("unchecked")
     static final Set<Class<?>> EXCLUDES = new HashSet<Class<?>>(Arrays.asList(Class.class,
             Boolean.class,
@@ -62,34 +65,75 @@
 
     private final WeakConcurrentSet<Class<?>> mocked;
 
-    private final String identifier;
-
-    private final MockMethodAdvice advice;
-
     private final BytecodeGenerator subclassEngine;
 
+    private final AsmVisitorWrapper mockTransformer;
+
     private volatile Throwable lastException;
 
     public InlineBytecodeGenerator(Instrumentation instrumentation, WeakConcurrentMap<Object, MockMethodInterceptor> mocks) {
+        preload();
         this.instrumentation = instrumentation;
         byteBuddy = new ByteBuddy()
-                .with(TypeValidation.DISABLED)
-                .with(Implementation.Context.Disabled.Factory.INSTANCE);
+            .with(TypeValidation.DISABLED)
+            .with(Implementation.Context.Disabled.Factory.INSTANCE)
+            .with(MethodGraph.Compiler.ForDeclaredMethods.INSTANCE);
         mocked = new WeakConcurrentSet<Class<?>>(WeakConcurrentSet.Cleaner.INLINE);
-        identifier = RandomString.make();
-        advice = new MockMethodAdvice(mocks, identifier);
+        String identifier = RandomString.make();
         subclassEngine = new TypeCachingBytecodeGenerator(new SubclassBytecodeGenerator(withDefaultConfiguration()
-                .withBinders(of(MockMethodAdvice.Identifier.class, identifier))
-                .to(MockMethodAdvice.ForReadObject.class), isAbstract().or(isNative()).or(isToString())), false);
-        MockMethodDispatcher.set(identifier, advice);
+            .withBinders(of(MockMethodAdvice.Identifier.class, identifier))
+            .to(MockMethodAdvice.ForReadObject.class), isAbstract().or(isNative()).or(isToString())), false);
+        mockTransformer = new AsmVisitorWrapper.ForDeclaredMethods()
+            .method(isVirtual()
+                    .and(not(isBridge().or(isHashCode()).or(isEquals()).or(isDefaultFinalizer())))
+                    .and(not(isDeclaredBy(nameStartsWith("java.")).<MethodDescription>and(isPackagePrivate()))),
+                Advice.withCustomMapping()
+                    .bind(MockMethodAdvice.Identifier.class, identifier)
+                    .to(MockMethodAdvice.class))
+            .method(isHashCode(),
+                Advice.withCustomMapping()
+                    .bind(MockMethodAdvice.Identifier.class, identifier)
+                    .to(MockMethodAdvice.ForHashCode.class))
+            .method(isEquals(),
+                Advice.withCustomMapping()
+                    .bind(MockMethodAdvice.Identifier.class, identifier)
+                    .to(MockMethodAdvice.ForEquals.class));
+        MockMethodDispatcher.set(identifier, new MockMethodAdvice(mocks, identifier));
         instrumentation.addTransformer(this, true);
     }
 
+    /**
+     * Mockito allows to mock about any type, including such types that we are relying on ourselves. This can cause a circularity:
+     * In order to check if an instance is a mock we need to look up if this instance is registered in the {@code mocked} set. But to look
+     * up this instance, we need to create key instances that rely on weak reference properties. Loading the later classes will happen before
+     * the key instances are completed what will cause Mockito to check if those key instances are themselves mocks what causes a loop which
+     * results in a circularity error. This is not normally a problem as we explicitly check if the instance that we investigate is one of
+     * our instance of which we hold a reference by reference equality what does not cause any code execution. But it seems like the load
+     * order plays a role here with unloaded types being loaded before we even get to check the mock instance property. To avoid this, we are
+     * making sure that crucuial JVM types are loaded before we create the first inline mock. Unfortunately, these types dependant on a JVM's
+     * implementation and we can only maintain types that we know of from well-known JVM implementations such as HotSpot and extend this list
+     * once we learn of further problematic types for future Java versions. To allow users to whitelist their own types, we do not also offer
+     * a property that allows running problematic tests before a new Mockito version can be released and that allows us to ask users to
+     * easily validate that whitelisting actually solves a problem as circularities could also be caused by other problems.
+     */
+    private static void preload() {
+        String preloads = System.getProperty(PRELOAD);
+        if (preloads == null) {
+            preloads = "java.lang.WeakPairMap,java.lang.WeakPairMap$Pair,java.lang.WeakPairMap$Pair$Weak";
+        }
+        for (String preload : preloads.split(",")) {
+            try {
+                Class.forName(preload, false, null);
+            } catch (ClassNotFoundException ignored) {
+            }
+        }
+    }
+
     @Override
     public <T> Class<? extends T> mockClass(MockFeatures<T> features) {
         boolean subclassingRequired = !features.interfaces.isEmpty()
-                || features.serializableMode != SerializableMode.NONE
-                || Modifier.isAbstract(features.mockedType.getModifiers());
+            || features.serializableMode != SerializableMode.NONE
+            || Modifier.isAbstract(features.mockedType.getModifiers());
 
         checkSupportedCombination(subclassingRequired, features);
 
@@ -157,29 +201,19 @@
                             String className,
                             Class<?> classBeingRedefined,
                             ProtectionDomain protectionDomain,
-                            byte[] classfileBuffer) throws IllegalClassFormatException {
+                            byte[] classfileBuffer) {
         if (classBeingRedefined == null
-                || !mocked.contains(classBeingRedefined)
-                || EXCLUDES.contains(classBeingRedefined)) {
+            || !mocked.contains(classBeingRedefined)
+            || EXCLUDES.contains(classBeingRedefined)) {
             return null;
         } else {
             try {
                 return byteBuddy.redefine(classBeingRedefined, ClassFileLocator.Simple.of(classBeingRedefined.getName(), classfileBuffer))
-                        // Note: The VM erases parameter meta data from the provided class file (bug). We just add this information manually.
-                        .visit(new ParameterWritingVisitorWrapper(classBeingRedefined))
-                        .visit(Advice.withCustomMapping()
-                                .bind(MockMethodAdvice.Identifier.class, identifier)
-                                .to(MockMethodAdvice.class).on(isVirtual()
-                                        .and(not(isBridge().or(isHashCode()).or(isEquals()).or(isDefaultFinalizer())))
-                                        .and(not(isDeclaredBy(nameStartsWith("java.")).<MethodDescription>and(isPackagePrivate())))))
-                        .visit(Advice.withCustomMapping()
-                                .bind(MockMethodAdvice.Identifier.class, identifier)
-                                .to(MockMethodAdvice.ForHashCode.class).on(isHashCode()))
-                        .visit(Advice.withCustomMapping()
-                                .bind(MockMethodAdvice.Identifier.class, identifier)
-                                .to(MockMethodAdvice.ForEquals.class).on(isEquals()))
-                        .make()
-                        .getBytes();
+                    // Note: The VM erases parameter meta data from the provided class file (bug). We just add this information manually.
+                    .visit(new ParameterWritingVisitorWrapper(classBeingRedefined))
+                    .visit(mockTransformer)
+                    .make()
+                    .getBytes();
             } catch (Throwable throwable) {
                 lastException = throwable;
                 return null;
@@ -214,7 +248,7 @@
             private final TypeDescription typeDescription;
 
             private ParameterAddingClassVisitor(ClassVisitor cv, TypeDescription typeDescription) {
-                super(Opcodes.ASM5, cv);
+                super(OpenedClassReader.ASM_API, cv);
                 this.typeDescription = typeDescription;
             }
 
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
index dc5c6e5..b659c73 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassBytecodeGenerator.java
@@ -38,6 +38,8 @@
 
 class SubclassBytecodeGenerator implements BytecodeGenerator {
 
+    private static final String CODEGEN_PACKAGE = "org.mockito.codegen.";
+
     private final SubclassLoader loader;
 
     private final ByteBuddy byteBuddy;
@@ -46,6 +48,11 @@
     private final Implementation readReplace;
     private final ElementMatcher<? super MethodDescription> matcher;
 
+    private final Implementation dispatcher = to(DispatcherDefaultingToRealMethod.class);
+    private final Implementation hashCode = to(MockMethodInterceptor.ForHashCode.class);
+    private final Implementation equals = to(MockMethodInterceptor.ForEquals.class);
+    private final Implementation writeReplace = to(MockMethodInterceptor.ForWriteReplace.class);
+
     public SubclassBytecodeGenerator() {
         this(new SubclassInjectionLoader());
     }
@@ -68,31 +75,32 @@
 
     @Override
     public <T> Class<? extends T> mockClass(MockFeatures<T> features) {
+        String name = nameFor(features.mockedType);
         DynamicType.Builder<T> builder =
                 byteBuddy.subclass(features.mockedType)
-                         .name(nameFor(features.mockedType))
+                         .name(name)
                          .ignoreAlso(isGroovyMethod())
                          .annotateType(features.stripAnnotations
                              ? new Annotation[0]
                              : features.mockedType.getAnnotations())
                          .implement(new ArrayList<Type>(features.interfaces))
                          .method(matcher)
-                           .intercept(to(DispatcherDefaultingToRealMethod.class))
+                           .intercept(dispatcher)
                            .transform(withModifiers(SynchronizationState.PLAIN))
                            .attribute(features.stripAnnotations
                                ? MethodAttributeAppender.NoOp.INSTANCE
                                : INCLUDING_RECEIVER)
                          .method(isHashCode())
-                           .intercept(to(MockMethodInterceptor.ForHashCode.class))
+                           .intercept(hashCode)
                          .method(isEquals())
-                           .intercept(to(MockMethodInterceptor.ForEquals.class))
+                           .intercept(equals)
                          .serialVersionUid(42L)
                          .defineField("mockitoInterceptor", MockMethodInterceptor.class, PRIVATE)
                          .implement(MockAccess.class)
                            .intercept(FieldAccessor.ofBeanProperty());
         if (features.serializableMode == SerializableMode.ACROSS_CLASSLOADERS) {
             builder = builder.implement(CrossClassLoaderSerializableMock.class)
-                             .intercept(to(MockMethodInterceptor.ForWriteReplace.class));
+                             .intercept(writeReplace);
         }
         if (readReplace != null) {
             builder = builder.defineMethod("readObject", void.class, Visibility.PRIVATE)
@@ -118,7 +126,7 @@
                 .or(hasParameters(whereAny(hasType(isPackagePrivate())))));
         }
         return builder.make()
-                      .load(classLoader, loader.getStrategy(features.mockedType))
+                      .load(classLoader, loader.resolveStrategy(features.mockedType, classLoader, name.startsWith(CODEGEN_PACKAGE)))
                       .getLoaded();
     }
 
@@ -132,7 +140,7 @@
         if (isComingFromJDK(type)
                 || isComingFromSignedJar(type)
                 || isComingFromSealedPackage(type)) {
-            typeName = "codegen." + typeName;
+            typeName = CODEGEN_PACKAGE + type.getSimpleName();
         }
         return String.format("%s$%s$%d", typeName, "MockitoMock", Math.abs(random.nextInt()));
     }
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java
index 20125f1..454dd8e 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassInjectionLoader.java
@@ -4,12 +4,104 @@
  */
 package org.mockito.internal.creation.bytebuddy;
 
+import net.bytebuddy.dynamic.loading.ClassInjector;
 import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
+import org.mockito.codegen.InjectionBase;
+import org.mockito.exceptions.base.MockitoException;
+import org.mockito.internal.util.Platform;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import static org.mockito.internal.util.StringUtil.join;
 
 class SubclassInjectionLoader implements SubclassLoader {
 
+    private static final String ERROR_MESSAGE = join("The current JVM does not support any class injection mechanism.",
+        "",
+        "Currently, Mockito supports injection via neither by method handle lookups or using sun.misc.Unsafe",
+        "Neither seems to be available on your current JVM.");
+
+    private final SubclassLoader loader;
+
+    SubclassInjectionLoader() {
+        if (!Boolean.getBoolean("org.mockito.internal.simulateJava11") && ClassInjector.UsingReflection.isAvailable()) {
+            this.loader = new WithReflection();
+        } else if (ClassInjector.UsingLookup.isAvailable()) {
+            this.loader = tryLookup();
+        } else {
+            throw new MockitoException(join(ERROR_MESSAGE, "", Platform.describe()));
+        }
+    }
+
+    private static SubclassLoader tryLookup() {
+        try {
+            Class<?> methodHandles = Class.forName("java.lang.invoke.MethodHandles");
+            Object lookup = methodHandles.getMethod("lookup").invoke(null);
+            Method privateLookupIn = methodHandles.getMethod("privateLookupIn", Class.class, Class.forName("java.lang.invoke.MethodHandles$Lookup"));
+            Object codegenLookup = privateLookupIn.invoke(null, InjectionBase.class, lookup);
+            return new WithLookup(lookup, codegenLookup, privateLookupIn);
+        } catch (Exception exception) {
+            throw new MockitoException(join(ERROR_MESSAGE, "", Platform.describe()), exception);
+        }
+    }
+
+    private static class WithReflection implements SubclassLoader {
+
+        @Override
+        public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean codegen) {
+            return ClassLoadingStrategy.Default.INJECTION.with(codegen ? InjectionBase.class.getProtectionDomain() : mockedType.getProtectionDomain());
+        }
+    }
+
+    private static class WithLookup implements SubclassLoader {
+
+        private final Object lookup;
+
+        private final Object codegenLookup;
+
+        private final Method privateLookupIn;
+
+        WithLookup(Object lookup, Object codegenLookup, Method privateLookupIn) {
+            this.lookup = lookup;
+            this.codegenLookup = codegenLookup;
+            this.privateLookupIn = privateLookupIn;
+        }
+
+        @Override
+        public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean codegen) {
+            if (codegen) {
+                return ClassLoadingStrategy.UsingLookup.of(codegenLookup);
+            } else if (classLoader != mockedType.getClassLoader()) {
+                return ClassLoadingStrategy.Default.WRAPPER.with(mockedType.getProtectionDomain());
+            } else {
+                try {
+                    Object privateLookup;
+                    try {
+                        privateLookup = privateLookupIn.invoke(null, mockedType, lookup);
+                    } catch (InvocationTargetException exception) {
+                        if (exception.getCause() instanceof IllegalAccessException) {
+                            return ClassLoadingStrategy.Default.WRAPPER.with(mockedType.getProtectionDomain());
+                        } else {
+                            throw exception.getCause();
+                        }
+                    }
+                    return ClassLoadingStrategy.UsingLookup.of(privateLookup);
+                } catch (Throwable exception) {
+                    throw new MockitoException(join(
+                        "The Java module system prevents Mockito from defining a mock class in the same package as " + mockedType,
+                        "",
+                        "To overcome this, you must open and export the mocked type to Mockito.",
+                        "Remember that you can also do so programmatically if the mocked class is defined by the same module as your test code",
+                        exception
+                    ));
+                }
+            }
+        }
+    }
+
     @Override
-    public ClassLoadingStrategy<ClassLoader> getStrategy(Class<?> mockedType) {
-        return ClassLoadingStrategy.Default.INJECTION.with(mockedType.getProtectionDomain());
+    public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean codegen) {
+        return loader.resolveStrategy(mockedType, classLoader, codegen);
     }
 }
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java
index 80b17ac..194c282 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/SubclassLoader.java
@@ -6,8 +6,18 @@
 
 import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
 
+/**
+ * A subclass loader is responsible for resolving a class loading strategy for a mock that is implemented as a subclass.
+ */
 public interface SubclassLoader {
 
-    ClassLoadingStrategy<ClassLoader> getStrategy(Class<?> mockedType);
-
+    /**
+     * Resolves a class loading strategy.
+     *
+     * @param mockedType  The type being mocked.
+     * @param classLoader The class loader being used.
+     * @param codegen     {@code true} if the mock is loaded in the {@code org.mockito.codegen} package.
+     * @return An appropriate class loading strategy.
+     */
+    ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean codegen);
 }
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java b/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java
index 34c31fe..ea51edf 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/TypeCachingBytecodeGenerator.java
@@ -36,7 +36,7 @@
                         public Class<?> call() throws Exception {
                             return bytecodeGenerator.mockClass(params);
                         }
-                    }, classLoader == null ? BOOTSTRAP_LOCK : classLoader);
+                    }, BOOTSTRAP_LOCK);
         } catch (IllegalArgumentException exception) {
             Throwable cause = exception.getCause();
             if (cause instanceof RuntimeException) {
diff --git a/src/main/java/org/mockito/internal/creation/settings/CreationSettings.java b/src/main/java/org/mockito/internal/creation/settings/CreationSettings.java
index 4befa99..03afd80 100644
--- a/src/main/java/org/mockito/internal/creation/settings/CreationSettings.java
+++ b/src/main/java/org/mockito/internal/creation/settings/CreationSettings.java
@@ -37,6 +37,7 @@
     private boolean useConstructor;
     private Object outerClassInstance;
     private Object[] constructorArgs;
+    protected boolean lenient;
 
     public CreationSettings() {}
 
@@ -55,6 +56,7 @@
         this.useConstructor = copy.isUsingConstructor();
         this.outerClassInstance = copy.getOuterClassInstance();
         this.constructorArgs = copy.getConstructorArgs();
+        this.lenient = copy.lenient;
     }
 
     @Override
@@ -153,4 +155,9 @@
     public boolean isStubOnly() {
         return stubOnly;
     }
+
+    @Override
+    public boolean isLenient() {
+        return lenient;
+    }
 }
diff --git a/src/main/java/org/mockito/internal/exceptions/Reporter.java b/src/main/java/org/mockito/internal/exceptions/Reporter.java
index 57094c0..2bc4445 100644
--- a/src/main/java/org/mockito/internal/exceptions/Reporter.java
+++ b/src/main/java/org/mockito/internal/exceptions/Reporter.java
@@ -8,6 +8,7 @@
 import org.mockito.exceptions.base.MockitoAssertionError;
 import org.mockito.exceptions.base.MockitoException;
 import org.mockito.exceptions.misusing.*;
+import org.mockito.exceptions.verification.MoreThanAllowedActualInvocations;
 import org.mockito.exceptions.verification.NeverWantedButInvoked;
 import org.mockito.exceptions.verification.NoInteractionsWanted;
 import org.mockito.exceptions.verification.SmartNullPointerException;
@@ -358,63 +359,71 @@
         ));
     }
 
-    public static MockitoAssertionError tooManyActualInvocations(int wantedCount, int actualCount, DescribedInvocation wanted, Location firstUndesired) {
-        String message = createTooManyInvocationsMessage(wantedCount, actualCount, wanted, firstUndesired);
+    public static MockitoAssertionError tooManyActualInvocations(int wantedCount, int actualCount, DescribedInvocation wanted, List<Location> locations) {
+        String message = createTooManyInvocationsMessage(wantedCount, actualCount, wanted, locations);
         return new TooManyActualInvocations(message);
     }
 
     private static String createTooManyInvocationsMessage(int wantedCount, int actualCount, DescribedInvocation wanted,
-                                                          Location firstUndesired) {
+                                                          List<Location> invocations) {
         return join(
                 wanted.toString(),
                 "Wanted " + pluralize(wantedCount) + ":",
                 new LocationImpl(),
-                "But was " + pluralize(actualCount) + ". Undesired invocation:",
-                firstUndesired,
+                "But was " + pluralize(actualCount) + ":",
+                createAllLocationsMessage(invocations),
                 ""
         );
     }
 
-    public static MockitoAssertionError neverWantedButInvoked(DescribedInvocation wanted, Location firstUndesired) {
+    public static MockitoAssertionError neverWantedButInvoked(DescribedInvocation wanted, List<Location> invocations) {
         return new NeverWantedButInvoked(join(
                 wanted.toString(),
                 "Never wanted here:",
                 new LocationImpl(),
                 "But invoked here:",
-                firstUndesired,
-                ""
+                createAllLocationsMessage(invocations)
         ));
     }
 
-    public static MockitoAssertionError tooManyActualInvocationsInOrder(int wantedCount, int actualCount, DescribedInvocation wanted, Location firstUndesired) {
-        String message = createTooManyInvocationsMessage(wantedCount, actualCount, wanted, firstUndesired);
+    public static MockitoAssertionError tooManyActualInvocationsInOrder(int wantedCount, int actualCount, DescribedInvocation wanted, List<Location> invocations) {
+        String message = createTooManyInvocationsMessage(wantedCount, actualCount, wanted, invocations);
         return new VerificationInOrderFailure(join(
                 "Verification in order failure:" + message
         ));
     }
 
-    private static String createTooLittleInvocationsMessage(org.mockito.internal.reporting.Discrepancy discrepancy, DescribedInvocation wanted,
-                                                            Location lastActualInvocation) {
-        String ending =
-                (lastActualInvocation != null) ? lastActualInvocation + "\n" : "\n";
+    private static String createAllLocationsMessage(List<Location> locations) {
+        if (locations == null) {
+            return "\n";
+        }
+        StringBuilder sb = new StringBuilder();
+        for (Location location : locations) {
+            sb.append(location).append("\n");
+        }
+        return sb.toString();
+    }
 
+    private static String createTooLittleInvocationsMessage(org.mockito.internal.reporting.Discrepancy discrepancy,
+                                                            DescribedInvocation wanted,
+                                                            List<Location> locations) {
         return join(
                 wanted.toString(),
                 "Wanted " + discrepancy.getPluralizedWantedCount() + (discrepancy.getWantedCount() == 0 ? "." : ":"),
                 new LocationImpl(),
                 "But was " + discrepancy.getPluralizedActualCount() + (discrepancy.getActualCount() == 0 ? "." : ":"),
-                ending
+                createAllLocationsMessage(locations)
         );
     }
 
-    public static MockitoAssertionError tooLittleActualInvocations(org.mockito.internal.reporting.Discrepancy discrepancy, DescribedInvocation wanted, Location lastActualLocation) {
-        String message = createTooLittleInvocationsMessage(discrepancy, wanted, lastActualLocation);
+    public static MockitoAssertionError tooLittleActualInvocations(org.mockito.internal.reporting.Discrepancy discrepancy, DescribedInvocation wanted, List<Location> allLocations) {
+        String message = createTooLittleInvocationsMessage(discrepancy, wanted, allLocations);
 
         return new TooLittleActualInvocations(message);
     }
 
-    public static MockitoAssertionError tooLittleActualInvocationsInOrder(org.mockito.internal.reporting.Discrepancy discrepancy, DescribedInvocation wanted, Location lastActualLocation) {
-        String message = createTooLittleInvocationsMessage(discrepancy, wanted, lastActualLocation);
+    public static MockitoAssertionError tooLittleActualInvocationsInOrder(org.mockito.internal.reporting.Discrepancy discrepancy, DescribedInvocation wanted, List<Location> locations) {
+        String message = createTooLittleInvocationsMessage(discrepancy, wanted, locations);
 
         return new VerificationInOrderFailure(join(
                 "Verification in order failure:" + message
@@ -509,9 +518,8 @@
         ));
     }
 
-
-    public static MockitoAssertionError wantedAtMostX(int maxNumberOfInvocations, int foundSize) {
-        return new MockitoAssertionError(join("Wanted at most " + pluralize(maxNumberOfInvocations) + " but was " + foundSize));
+    public static MoreThanAllowedActualInvocations wantedAtMostX(int maxNumberOfInvocations, int foundSize) {
+        return new MoreThanAllowedActualInvocations(join("Wanted at most " + pluralize(maxNumberOfInvocations) + " but was " + foundSize));
     }
 
     public static MockitoException misplacedArgumentMatcher(List<LocalizedMatcher> lastMatchers) {
diff --git a/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java b/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java
index f5216ee..9892422 100644
--- a/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java
+++ b/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java
@@ -7,6 +7,7 @@
 import org.hamcrest.Matcher;
 import org.hamcrest.StringDescription;
 import org.mockito.ArgumentMatcher;
+import org.mockito.internal.matchers.VarargMatcher;
 
 public class HamcrestArgumentMatcher<T> implements ArgumentMatcher<T> {
 
@@ -20,6 +21,10 @@
         return this.matcher.matches(argument);
     }
 
+    public boolean isVarargMatcher() {
+        return matcher instanceof VarargMatcher;
+    }
+
     public String toString() {
         //TODO SF add unit tests and integ test coverage for describeTo()
         return StringDescription.toString(matcher);
diff --git a/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java b/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java
index 57a9d43..a5c6458 100644
--- a/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java
+++ b/src/main/java/org/mockito/internal/handler/MockHandlerImpl.java
@@ -7,7 +7,6 @@
 import org.mockito.internal.creation.settings.CreationSettings;
 import org.mockito.internal.invocation.InvocationMatcher;
 import org.mockito.internal.invocation.MatchersBinder;
-import org.mockito.internal.listeners.StubbingLookupListener;
 import org.mockito.internal.stubbing.InvocationContainerImpl;
 import org.mockito.internal.stubbing.OngoingStubbingImpl;
 import org.mockito.internal.stubbing.StubbedInvocationMatcher;
@@ -20,9 +19,7 @@
 import org.mockito.mock.MockCreationSettings;
 import org.mockito.verification.VerificationMode;
 
-import java.util.List;
-
-import static org.mockito.internal.exceptions.Reporter.stubPassedToVerify;
+import static org.mockito.internal.listeners.StubbingLookupNotifier.notifyStubbedAnswerLookup;
 import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
 
 /**
@@ -44,7 +41,7 @@
         this.mockSettings = mockSettings;
 
         this.matchersBinder = new MatchersBinder();
-        this.invocationContainer = new InvocationContainerImpl( mockSettings);
+        this.invocationContainer = new InvocationContainerImpl(mockSettings);
     }
 
     public Object handle(Invocation invocation) throws Throwable {
@@ -71,7 +68,7 @@
             // We need to check if verification was started on the correct mock
             // - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)
             if (((MockAwareVerificationMode) verificationMode).getMock() == invocation.getMock()) {
-                VerificationDataImpl data = createVerificationData(invocationContainer, invocationMatcher);
+                VerificationDataImpl data = new VerificationDataImpl(invocationContainer, invocationMatcher);
                 verificationMode.verify(data);
                 return null;
             } else {
@@ -88,7 +85,9 @@
 
         // look for existing answer for this invocation
         StubbedInvocationMatcher stubbing = invocationContainer.findAnswerFor(invocation);
-        notifyStubbedAnswerLookup(invocation, stubbing);
+        // TODO #793 - when completed, we should be able to get rid of the casting below
+        notifyStubbedAnswerLookup(invocation, stubbing, invocationContainer.getStubbingsAscending(),
+                                  (CreationSettings) mockSettings);
 
         if (stubbing != null) {
             stubbing.captureArgumentsFrom(invocation);
@@ -121,21 +120,4 @@
     public InvocationContainer getInvocationContainer() {
         return invocationContainer;
     }
-
-    private VerificationDataImpl createVerificationData(InvocationContainerImpl invocationContainer, InvocationMatcher invocationMatcher) {
-        if (mockSettings.isStubOnly()) {
-            throw stubPassedToVerify();     // this throws an exception
-        }
-
-        return new VerificationDataImpl(invocationContainer, invocationMatcher);
-    }
-
-    private void notifyStubbedAnswerLookup(Invocation invocation, StubbedInvocationMatcher exception) {
-        //TODO #793 - when completed, we should be able to get rid of the casting below
-        List<StubbingLookupListener> listeners = ((CreationSettings) mockSettings).getStubbingLookupListeners();
-        for (StubbingLookupListener listener : listeners) {
-            listener.onStubbingLookup(invocation, exception);
-        }
-    }
 }
-
diff --git a/src/main/java/org/mockito/internal/invocation/InvocationsFinder.java b/src/main/java/org/mockito/internal/invocation/InvocationsFinder.java
index 57c335f..260321b 100644
--- a/src/main/java/org/mockito/internal/invocation/InvocationsFinder.java
+++ b/src/main/java/org/mockito/internal/invocation/InvocationsFinder.java
@@ -138,6 +138,14 @@
         return unverified;
     }
 
+    public static List<Location> getAllLocations(List<Invocation> invocations) {
+        List<Location> locations = new LinkedList<Location>();
+        for (Invocation invocation : invocations) {
+            locations.add(invocation.getLocation());
+        }
+        return locations;
+    }
+
     private static class RemoveNotMatching implements Filter<Invocation> {
         private final MatchableInvocation wanted;
 
diff --git a/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java b/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java
index e085c25..e47156f 100644
--- a/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java
+++ b/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java
@@ -12,6 +12,7 @@
 import java.util.List;
 
 import org.mockito.ArgumentMatcher;
+import org.mockito.internal.hamcrest.HamcrestArgumentMatcher;
 import org.mockito.internal.matchers.CapturingMatcher;
 import org.mockito.internal.matchers.VarargMatcher;
 import org.mockito.invocation.Invocation;
@@ -95,15 +96,19 @@
             return ONE_MATCHER_PER_ARGUMENT;
         }
 
-        if (rawArguments == matcherCount && isLastMatcherVargargMatcher(matchers)) {
+        if (rawArguments == matcherCount && isLastMatcherVarargMatcher(matchers)) {
             return MATCH_EACH_VARARGS_WITH_LAST_MATCHER;
         }
 
         return ERROR_UNSUPPORTED_NUMBER_OF_MATCHERS;
     }
 
-    private static boolean isLastMatcherVargargMatcher(final List<ArgumentMatcher<?>> matchers) {
-        return lastMatcher(matchers) instanceof VarargMatcher;
+    private static boolean isLastMatcherVarargMatcher(final List<ArgumentMatcher<?>> matchers) {
+        ArgumentMatcher<?> argumentMatcher = lastMatcher(matchers);
+        if (argumentMatcher instanceof HamcrestArgumentMatcher<?>) {
+           return  ((HamcrestArgumentMatcher<?>) argumentMatcher).isVarargMatcher();
+        }
+        return argumentMatcher instanceof VarargMatcher;
     }
 
     private static List<ArgumentMatcher<?>> appendLastMatcherNTimes(List<ArgumentMatcher<?>> matchers, int timesToAppendLastMatcher) {
diff --git a/src/main/java/org/mockito/internal/invocation/UnusedStubsFinder.java b/src/main/java/org/mockito/internal/invocation/UnusedStubsFinder.java
index 0f9ac6d..5aec36d 100644
--- a/src/main/java/org/mockito/internal/invocation/UnusedStubsFinder.java
+++ b/src/main/java/org/mockito/internal/invocation/UnusedStubsFinder.java
@@ -23,7 +23,7 @@
     public List<Invocation> find(List<?> mocks) {
         List<Invocation> unused = new LinkedList<Invocation>();
         for (Object mock : mocks) {
-            List<Stubbing> fromSingleMock = MockUtil.getInvocationContainer(mock).getStubbedInvocations();
+            List<Stubbing> fromSingleMock = MockUtil.getInvocationContainer(mock).getStubbingsDescending();
             for(Stubbing s : fromSingleMock) {
                 if (!s.wasUsed()) {
                      unused.add(s.getInvocation());
diff --git a/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java b/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java
index c7e2551..4885d63 100644
--- a/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java
+++ b/src/main/java/org/mockito/internal/junit/DefaultStubbingLookupListener.java
@@ -5,9 +5,10 @@
 package org.mockito.internal.junit;
 
 import org.mockito.internal.exceptions.Reporter;
+import org.mockito.internal.listeners.StubbingLookupEvent;
 import org.mockito.internal.listeners.StubbingLookupListener;
+import org.mockito.internal.stubbing.UnusedStubbingReporting;
 import org.mockito.invocation.Invocation;
-import org.mockito.invocation.MatchableInvocation;
 import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Stubbing;
 
@@ -15,7 +16,7 @@
 import java.util.LinkedList;
 import java.util.List;
 
-import static org.mockito.Mockito.mockingDetails;
+import static org.mockito.internal.stubbing.StrictnessSelector.determineStrictness;
 
 /**
  * Default implementation of stubbing lookup listener.
@@ -30,31 +31,33 @@
         this.currentStrictness = strictness;
     }
 
-    public void onStubbingLookup(Invocation invocation, MatchableInvocation stubbingFound) {
-        if (currentStrictness != Strictness.STRICT_STUBS) {
+    public void onStubbingLookup(StubbingLookupEvent event) {
+        Strictness actualStrictness = determineStrictness(event.getStubbingFound(), event.getMockSettings(), currentStrictness);
+
+        if (actualStrictness != Strictness.STRICT_STUBS) {
             return;
         }
 
-        if (stubbingFound == null) {
+        if (event.getStubbingFound() == null) {
             //If stubbing was not found for invocation it means that either the mock invocation was not stubbed or
             //we have a stubbing arg mismatch.
-            List<Invocation> argMismatchStubbings = potentialArgMismatches(invocation);
+            List<Invocation> argMismatchStubbings = potentialArgMismatches(event.getInvocation(), event.getAllStubbings());
             if (!argMismatchStubbings.isEmpty()) {
                 mismatchesReported = true;
-                Reporter.potentialStubbingProblem(invocation, argMismatchStubbings);
+                Reporter.potentialStubbingProblem(event.getInvocation(), argMismatchStubbings);
             }
         } else {
             //when strict stubs are in use, every time a stub is realized in the code it is implicitly marked as verified
             //this way, the users don't have to repeat themselves to verify stubbed invocations (DRY)
-            invocation.markVerified();
+            event.getInvocation().markVerified();
         }
     }
 
-    private static List<Invocation> potentialArgMismatches(Invocation invocation) {
+    private static List<Invocation> potentialArgMismatches(Invocation invocation, Collection<Stubbing> stubbings) {
         List<Invocation> matchingStubbings = new LinkedList<Invocation>();
-        Collection<Stubbing> stubbings = mockingDetails(invocation.getMock()).getStubbings();
         for (Stubbing s : stubbings) {
-            if (!s.wasUsed() && s.getInvocation().getMethod().getName().equals(invocation.getMethod().getName())) {
+            if (UnusedStubbingReporting.shouldBeReported(s)
+                && s.getInvocation().getMethod().getName().equals(invocation.getMethod().getName())) {
                 matchingStubbings.add(s.getInvocation());
             }
         }
diff --git a/src/main/java/org/mockito/internal/junit/UnusedStubbings.java b/src/main/java/org/mockito/internal/junit/UnusedStubbings.java
index 5b6434d..3505d2c 100644
--- a/src/main/java/org/mockito/internal/junit/UnusedStubbings.java
+++ b/src/main/java/org/mockito/internal/junit/UnusedStubbings.java
@@ -6,11 +6,11 @@
 
 import org.mockito.internal.exceptions.Reporter;
 import org.mockito.internal.util.MockitoLogger;
-import org.mockito.internal.util.collections.ListUtil;
 import org.mockito.invocation.Invocation;
 import org.mockito.stubbing.Stubbing;
 
 import java.util.Collection;
+import java.util.LinkedList;
 import java.util.List;
 
 /**
@@ -47,16 +47,19 @@
         return unused.toString();
     }
 
-    public void reportUnused() {
-        if (!unused.isEmpty()) {
-            List<Invocation> invocations = ListUtil.convert(unused, (ListUtil.Converter) new ListUtil.Converter<Stubbing, Invocation>() {
-                public Invocation convert(Stubbing s) {
-                    return s.getInvocation();
-                }
-            });
-
-
-            Reporter.unncessaryStubbingException(invocations);
+    void reportUnused() {
+        if (unused.isEmpty()) {
+            return;
         }
+
+        List<Invocation> invocations = new LinkedList<Invocation>();
+        for (Stubbing stubbing : unused) {
+            invocations.add(stubbing.getInvocation());
+        }
+        if (invocations.isEmpty()) {
+            return;
+        }
+
+        Reporter.unncessaryStubbingException(invocations);
     }
 }
diff --git a/src/main/java/org/mockito/internal/junit/UnusedStubbingsFinder.java b/src/main/java/org/mockito/internal/junit/UnusedStubbingsFinder.java
index 715c393..14c61c5 100644
--- a/src/main/java/org/mockito/internal/junit/UnusedStubbingsFinder.java
+++ b/src/main/java/org/mockito/internal/junit/UnusedStubbingsFinder.java
@@ -4,12 +4,18 @@
  */
 package org.mockito.internal.junit;
 
-import org.mockito.stubbing.Stubbing;
 import org.mockito.internal.invocation.finder.AllInvocationsFinder;
+import org.mockito.internal.stubbing.UnusedStubbingReporting;
 import org.mockito.internal.util.collections.ListUtil.Filter;
 import org.mockito.invocation.Invocation;
+import org.mockito.stubbing.Stubbing;
 
-import java.util.*;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import static org.mockito.internal.util.collections.ListUtil.filter;
 
@@ -19,14 +25,15 @@
 public class UnusedStubbingsFinder {
 
     /**
-     * Gets all unused stubbings for given set of mock objects, in order
+     * Gets all unused stubbings for given set of mock objects, in order.
+     * Stubbings explicitily marked as LENIENT are not included.
      */
     public UnusedStubbings getUnusedStubbings(Iterable<Object> mocks) {
         Set<Stubbing> stubbings = AllInvocationsFinder.findStubbings(mocks);
 
         List<Stubbing> unused = filter(stubbings, new Filter<Stubbing>() {
             public boolean isOut(Stubbing s) {
-                return s.wasUsed();
+                return !UnusedStubbingReporting.shouldBeReported(s);
             }
         });
 
@@ -50,7 +57,7 @@
         //note that those are _not_ locations where the stubbings was used
         Set<String> locationsOfUsedStubbings = new HashSet<String>();
         for (Stubbing s : stubbings) {
-            if (s.wasUsed()) {
+            if (!UnusedStubbingReporting.shouldBeReported(s)) {
                 String location = s.getInvocation().getLocation().toString();
                 locationsOfUsedStubbings.add(location);
             }
diff --git a/src/main/java/org/mockito/internal/listeners/StubbingLookupEvent.java b/src/main/java/org/mockito/internal/listeners/StubbingLookupEvent.java
new file mode 100644
index 0000000..0d45edd
--- /dev/null
+++ b/src/main/java/org/mockito/internal/listeners/StubbingLookupEvent.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.listeners;
+
+import org.mockito.invocation.Invocation;
+import org.mockito.mock.MockCreationSettings;
+import org.mockito.stubbing.Stubbing;
+
+import java.util.Collection;
+
+/**
+ * Represent an information about the looked up stubbing
+ */
+public interface StubbingLookupEvent {
+    /**
+     * @return The invocation that causes stubbing lookup
+     */
+    Invocation getInvocation();
+
+    /**
+     * @return Looked up stubbing. It can be <code>null</code>, which indicates that the invocation was not stubbed
+     */
+    Stubbing getStubbingFound();
+
+    /**
+     * @return All stubbings declared on the mock object that we are invoking
+     */
+    Collection<Stubbing> getAllStubbings();
+
+    /**
+     * @return Settings of the mock object that we are invoking
+     */
+    MockCreationSettings getMockSettings();
+}
diff --git a/src/main/java/org/mockito/internal/listeners/StubbingLookupListener.java b/src/main/java/org/mockito/internal/listeners/StubbingLookupListener.java
index 81cf537..6fa37a1 100644
--- a/src/main/java/org/mockito/internal/listeners/StubbingLookupListener.java
+++ b/src/main/java/org/mockito/internal/listeners/StubbingLookupListener.java
@@ -4,9 +4,6 @@
  */
 package org.mockito.internal.listeners;
 
-import org.mockito.invocation.Invocation;
-import org.mockito.invocation.MatchableInvocation;
-
 /**
  * Listens to attempts to look up stubbing answer for given mocks. This class is internal for now.
  * <p>
@@ -27,11 +24,7 @@
     /**
      * Called by the framework when Mockito looked up an answer for invocation on a mock.
      *
-     * TODO when making this public, we should have an event object instead of 2 arguments in the listener.
-     *
-     * @param invocation the invocation on the mock
-     * @param stubbingFound - can be null - it indicates that the invocation was not stubbed.
+     * @param stubbingLookupEvent - Information about the looked up stubbing
      */
-    void onStubbingLookup(Invocation invocation, MatchableInvocation stubbingFound);
-
+    void onStubbingLookup(StubbingLookupEvent stubbingLookupEvent);
 }
diff --git a/src/main/java/org/mockito/internal/listeners/StubbingLookupNotifier.java b/src/main/java/org/mockito/internal/listeners/StubbingLookupNotifier.java
new file mode 100644
index 0000000..3e55001
--- /dev/null
+++ b/src/main/java/org/mockito/internal/listeners/StubbingLookupNotifier.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.listeners;
+
+import org.mockito.internal.creation.settings.CreationSettings;
+import org.mockito.invocation.Invocation;
+import org.mockito.mock.MockCreationSettings;
+import org.mockito.stubbing.Stubbing;
+
+import java.util.Collection;
+import java.util.List;
+
+public class StubbingLookupNotifier {
+
+    public static void notifyStubbedAnswerLookup(Invocation invocation, Stubbing stubbingFound,
+                                                 Collection<Stubbing> allStubbings, CreationSettings creationSettings) {
+        List<StubbingLookupListener> listeners = creationSettings.getStubbingLookupListeners();
+        if (listeners.isEmpty()) {
+            return;
+        }
+        StubbingLookupEvent event = new Event(invocation, stubbingFound, allStubbings, creationSettings);
+        for (StubbingLookupListener listener : listeners) {
+            listener.onStubbingLookup(event);
+        }
+    }
+
+    static class Event implements StubbingLookupEvent {
+        final private Invocation invocation;
+        final private Stubbing stubbing;
+        final private Collection<Stubbing> allStubbings;
+        final private MockCreationSettings mockSettings;
+
+        public Event(Invocation invocation,
+                     Stubbing stubbing,
+                     Collection<Stubbing> allStubbings,
+                     MockCreationSettings mockSettings) {
+            this.invocation = invocation;
+            this.stubbing = stubbing;
+            this.allStubbings = allStubbings;
+            this.mockSettings = mockSettings;
+        }
+
+        @Override
+        public Invocation getInvocation() {
+            return invocation;
+        }
+
+        @Override
+        public Stubbing getStubbingFound() {
+            return stubbing;
+        }
+
+        @Override
+        public Collection<Stubbing> getAllStubbings() {
+            return allStubbings;
+        }
+
+        @Override
+        public MockCreationSettings getMockSettings() {
+            return mockSettings;
+        }
+    }
+}
diff --git a/src/main/java/org/mockito/internal/matchers/Any.java b/src/main/java/org/mockito/internal/matchers/Any.java
index f9f0069..58b6404 100644
--- a/src/main/java/org/mockito/internal/matchers/Any.java
+++ b/src/main/java/org/mockito/internal/matchers/Any.java
@@ -9,13 +9,10 @@
 
 import org.mockito.ArgumentMatcher;
 
-public class Any implements ArgumentMatcher<Object>, VarargMatcher ,Serializable {
+public class Any implements ArgumentMatcher<Object>, VarargMatcher, Serializable {
 
     public static final Any ANY = new Any();
 
-    private Any() {
-    }
-
     public boolean matches(Object actual) {
         return true;
     }
diff --git a/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java b/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java
index ddb9a8d..6dd99cd 100644
--- a/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java
+++ b/src/main/java/org/mockito/internal/stubbing/BaseStubbing.java
@@ -24,7 +24,8 @@
     public OngoingStubbing<T> thenReturn(T value, T... values) {
         OngoingStubbing<T> stubbing = thenReturn(value);
         if (values == null) {
-            // TODO below does not seem right
+            // For no good reason we're configuring null answer here
+            // This has been like that since forever, so let's keep it for compatibility (unless users complain)
             return stubbing.thenReturn(null);
         }
         for (T v : values) {
@@ -65,7 +66,7 @@
     @Override
     public OngoingStubbing<T> thenThrow(Class<? extends Throwable> toBeThrown, Class<? extends Throwable>... nextToBeThrown) {
         if (nextToBeThrown == null) {
-            thenThrow((Class<Throwable>) null);
+            return thenThrow((Class<Throwable>) null);
         }
         OngoingStubbing<T> stubbing = thenThrow(toBeThrown);
         for (Class<? extends Throwable> t : nextToBeThrown) {
diff --git a/src/main/java/org/mockito/internal/stubbing/DefaultLenientStubber.java b/src/main/java/org/mockito/internal/stubbing/DefaultLenientStubber.java
new file mode 100644
index 0000000..0f3fe07
--- /dev/null
+++ b/src/main/java/org/mockito/internal/stubbing/DefaultLenientStubber.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.stubbing;
+
+import org.mockito.internal.MockitoCore;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+import org.mockito.stubbing.LenientStubber;
+import org.mockito.stubbing.OngoingStubbing;
+import org.mockito.stubbing.Stubber;
+
+public class DefaultLenientStubber implements LenientStubber {
+
+    private final static MockitoCore MOCKITO_CORE = new MockitoCore();
+
+    @Override
+    public Stubber doThrow(Throwable... toBeThrown) {
+        return stubber().doThrow(toBeThrown);
+    }
+
+    @Override
+    public Stubber doThrow(Class<? extends Throwable> toBeThrown) {
+        return stubber().doThrow(toBeThrown);
+    }
+
+    @Override
+    public Stubber doThrow(Class<? extends Throwable> toBeThrown, Class<? extends Throwable>... nextToBeThrown) {
+        return stubber().doThrow(toBeThrown, nextToBeThrown);
+    }
+
+    @Override
+    public Stubber doAnswer(Answer answer) {
+        return stubber().doAnswer(answer);
+    }
+
+    @Override
+    public Stubber doNothing() {
+        return stubber().doNothing();
+    }
+
+    @Override
+    public Stubber doReturn(Object toBeReturned) {
+        return stubber().doReturn(toBeReturned);
+    }
+
+    @Override
+    public Stubber doReturn(Object toBeReturned, Object... nextToBeReturned) {
+        return stubber().doReturn(toBeReturned, nextToBeReturned);
+    }
+
+    @Override
+    public Stubber doCallRealMethod() {
+        return stubber().doCallRealMethod();
+    }
+
+    @Override
+    public <T> OngoingStubbing<T> when(T methodCall) {
+        OngoingStubbingImpl<T> ongoingStubbing = (OngoingStubbingImpl) MOCKITO_CORE.when(methodCall);
+        ongoingStubbing.setStrictness(Strictness.LENIENT);
+        return ongoingStubbing;
+    }
+
+    private static Stubber stubber() {
+        return MOCKITO_CORE.stubber(Strictness.LENIENT);
+    }
+}
diff --git a/src/main/java/org/mockito/internal/stubbing/DoAnswerStyleStubbing.java b/src/main/java/org/mockito/internal/stubbing/DoAnswerStyleStubbing.java
new file mode 100644
index 0000000..56491b8
--- /dev/null
+++ b/src/main/java/org/mockito/internal/stubbing/DoAnswerStyleStubbing.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.stubbing;
+
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Holds answers declared using 'doAnswer' stubbing style.
+ */
+class DoAnswerStyleStubbing implements Serializable {
+
+    private final List<Answer<?>> answers = new ArrayList<Answer<?>>();
+    private Strictness stubbingStrictness;
+
+    void setAnswers(List<Answer<?>> answers, Strictness stubbingStrictness) {
+        this.stubbingStrictness = stubbingStrictness;
+        this.answers.addAll(answers);
+    }
+
+    boolean isSet() {
+        return answers.isEmpty();
+    }
+
+    void clear() {
+        answers.clear();
+        stubbingStrictness = null;
+    }
+
+    List<Answer<?>> getAnswers() {
+        return answers;
+    }
+
+    Strictness getStubbingStrictness() {
+        return stubbingStrictness;
+    }
+}
diff --git a/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java b/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java
index 120320b..6c98f37 100644
--- a/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java
+++ b/src/main/java/org/mockito/internal/stubbing/InvocationContainerImpl.java
@@ -12,12 +12,14 @@
 import org.mockito.invocation.InvocationContainer;
 import org.mockito.invocation.MatchableInvocation;
 import org.mockito.mock.MockCreationSettings;
+import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Answer;
 import org.mockito.stubbing.Stubbing;
 import org.mockito.stubbing.ValidableAnswer;
 
 import java.io.Serializable;
-import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -28,13 +30,16 @@
 
     private static final long serialVersionUID = -5334301962749537177L;
     private final LinkedList<StubbedInvocationMatcher> stubbed = new LinkedList<StubbedInvocationMatcher>();
-    private final List<Answer<?>> answersForStubbing = new ArrayList<Answer<?>>();
+    private final DoAnswerStyleStubbing doAnswerStyleStubbing;
     private final RegisteredInvocations registeredInvocations;
+    private final Strictness mockStrictness;
 
     private MatchableInvocation invocationForStubbing;
 
     public InvocationContainerImpl(MockCreationSettings mockSettings) {
         this.registeredInvocations = createRegisteredInvocations(mockSettings);
+        this.mockStrictness = mockSettings.isLenient() ? Strictness.LENIENT : null;
+        this.doAnswerStyleStubbing = new DoAnswerStyleStubbing();
     }
 
     public void setInvocationForPotentialStubbing(MatchableInvocation invocation) {
@@ -46,19 +51,19 @@
         this.invocationForStubbing = invocationMatcher;
     }
 
-    public void addAnswer(Answer answer) {
+    public void addAnswer(Answer answer, Strictness stubbingStrictness) {
         registeredInvocations.removeLast();
-        addAnswer(answer, false);
+        addAnswer(answer, false, stubbingStrictness);
     }
 
     public void addConsecutiveAnswer(Answer answer) {
-        addAnswer(answer, true);
+        addAnswer(answer, true, null);
     }
 
     /**
      * Adds new stubbed answer and returns the invocation matcher the answer was added to.
      */
-    public StubbedInvocationMatcher addAnswer(Answer answer, boolean isConsecutive) {
+    public StubbedInvocationMatcher addAnswer(Answer answer, boolean isConsecutive, Strictness stubbingStrictness) {
         Invocation invocation = invocationForStubbing.getInvocation();
         mockingProgress().stubbingCompleted();
         if (answer instanceof ValidableAnswer) {
@@ -69,7 +74,8 @@
             if (isConsecutive) {
                 stubbed.getFirst().addAnswer(answer);
             } else {
-                stubbed.addFirst(new StubbedInvocationMatcher(invocationForStubbing, answer));
+                Strictness effectiveStrictness = stubbingStrictness != null ? stubbingStrictness : this.mockStrictness;
+                stubbed.addFirst(new StubbedInvocationMatcher(answer, invocationForStubbing, effectiveStrictness));
             }
             return stubbed.getFirst();
         }
@@ -84,6 +90,7 @@
             for (StubbedInvocationMatcher s : stubbed) {
                 if (s.matches(invocation)) {
                     s.markStubUsed(invocation);
+                    //TODO we should mark stubbed at the point of stubbing, not at the point where the stub is being used
                     invocation.markStubbed(new StubInfoImpl(s));
                     return s;
                 }
@@ -93,12 +100,15 @@
         return null;
     }
 
-    public void setAnswersForStubbing(List<Answer<?>> answers) {
-        answersForStubbing.addAll(answers);
+    /**
+     * Sets the answers declared with 'doAnswer' style.
+     */
+    public void setAnswersForStubbing(List<Answer<?>> answers, Strictness strictness) {
+        doAnswerStyleStubbing.setAnswers(answers, strictness);
     }
 
     public boolean hasAnswersForStubbing() {
-        return !answersForStubbing.isEmpty();
+        return !doAnswerStyleStubbing.isSet();
     }
 
     public boolean hasInvocationForPotentialStubbing() {
@@ -108,10 +118,10 @@
     public void setMethodForStubbing(MatchableInvocation invocation) {
         invocationForStubbing = invocation;
         assert hasAnswersForStubbing();
-        for (int i = 0; i < answersForStubbing.size(); i++) {
-            addAnswer(answersForStubbing.get(i), i != 0);
+        for (int i = 0; i < doAnswerStyleStubbing.getAnswers().size(); i++) {
+            addAnswer(doAnswerStyleStubbing.getAnswers().get(i), i != 0, doAnswerStyleStubbing.getStubbingStrictness());
         }
-        answersForStubbing.clear();
+        doAnswerStyleStubbing.clear();
     }
 
     @Override
@@ -127,10 +137,22 @@
         registeredInvocations.clear();
     }
 
-    public List<Stubbing> getStubbedInvocations() {
+    /**
+     * Stubbings in descending order, most recent first
+     */
+    public List<Stubbing> getStubbingsDescending() {
         return (List) stubbed;
     }
 
+    /**
+     * Stubbings in ascending order, most recent last
+     */
+    public Collection<Stubbing> getStubbingsAscending() {
+        List<Stubbing> result = new LinkedList<Stubbing>(stubbed);
+        Collections.reverse(result);
+        return result;
+    }
+
     public Object invokedMock() {
         return invocationForStubbing.getInvocation().getMock();
     }
diff --git a/src/main/java/org/mockito/internal/stubbing/OngoingStubbingImpl.java b/src/main/java/org/mockito/internal/stubbing/OngoingStubbingImpl.java
index 78a1027..cd27c39 100644
--- a/src/main/java/org/mockito/internal/stubbing/OngoingStubbingImpl.java
+++ b/src/main/java/org/mockito/internal/stubbing/OngoingStubbingImpl.java
@@ -5,16 +5,18 @@
 package org.mockito.internal.stubbing;
 
 import org.mockito.invocation.Invocation;
+import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Answer;
 import org.mockito.stubbing.OngoingStubbing;
 
-import static org.mockito.internal.exceptions.Reporter.incorrectUseOfApi;
-
 import java.util.List;
 
+import static org.mockito.internal.exceptions.Reporter.incorrectUseOfApi;
+
 public class OngoingStubbingImpl<T> extends BaseStubbing<T> {
 
     private final InvocationContainerImpl invocationContainer;
+    private Strictness strictness;
 
     public OngoingStubbingImpl(InvocationContainerImpl invocationContainer) {
         this.invocationContainer = invocationContainer;
@@ -26,7 +28,7 @@
             throw incorrectUseOfApi();
         }
 
-        invocationContainer.addAnswer(answer);
+        invocationContainer.addAnswer(answer, strictness);
         return new ConsecutiveStubbing<T>(invocationContainer);
     }
 
@@ -45,6 +47,10 @@
     public <M> M getMock() {
         return (M) invocationContainer.invokedMock();
     }
+
+    public void setStrictness(Strictness strictness) {
+        this.strictness = strictness;
+    }
 }
 
 
diff --git a/src/main/java/org/mockito/internal/stubbing/StrictnessSelector.java b/src/main/java/org/mockito/internal/stubbing/StrictnessSelector.java
new file mode 100644
index 0000000..6009e93
--- /dev/null
+++ b/src/main/java/org/mockito/internal/stubbing/StrictnessSelector.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.stubbing;
+
+import org.mockito.mock.MockCreationSettings;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Stubbing;
+
+/**
+ * Helps determining the actual strictness given that it can be configured in multiple ways (at mock, at stubbing, in rule)
+ */
+public class StrictnessSelector {
+
+    /**
+     * Determines the actual strictness in the following importance order:
+     * 1st - strictness configured when declaring stubbing;
+     * 2nd - strictness configured at mock level;
+     * 3rd - strictness configured at test level (rule, mockito session)
+     *
+     * @param stubbing stubbing to check for strictness. Null permitted.
+     * @param mockSettings settings of the mock object, may or may not have strictness configured. Must not be null.
+     * @param testLevelStrictness strictness configured using the test-level configuration (rule, mockito session). Null permitted.
+     *
+     * @return actual strictness, can be null.
+     */
+    public static Strictness determineStrictness(Stubbing stubbing, MockCreationSettings mockSettings, Strictness testLevelStrictness) {
+        if (stubbing != null && stubbing.getStrictness() != null) {
+            return stubbing.getStrictness();
+        }
+
+        if (mockSettings.isLenient()) {
+            return Strictness.LENIENT;
+        }
+
+        return testLevelStrictness;
+    }
+}
diff --git a/src/main/java/org/mockito/internal/stubbing/StubbedInvocationMatcher.java b/src/main/java/org/mockito/internal/stubbing/StubbedInvocationMatcher.java
index 4518210..e7ccac4 100644
--- a/src/main/java/org/mockito/internal/stubbing/StubbedInvocationMatcher.java
+++ b/src/main/java/org/mockito/internal/stubbing/StubbedInvocationMatcher.java
@@ -5,11 +5,12 @@
 package org.mockito.internal.stubbing;
 
 import org.mockito.internal.invocation.InvocationMatcher;
-import org.mockito.invocation.MatchableInvocation;
-import org.mockito.stubbing.Stubbing;
 import org.mockito.invocation.DescribedInvocation;
 import org.mockito.invocation.InvocationOnMock;
+import org.mockito.invocation.MatchableInvocation;
+import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Answer;
+import org.mockito.stubbing.Stubbing;
 
 import java.io.Serializable;
 import java.util.Queue;
@@ -20,10 +21,12 @@
 
     private static final long serialVersionUID = 4919105134123672727L;
     private final Queue<Answer> answers = new ConcurrentLinkedQueue<Answer>();
+    private final Strictness strictness;
     private DescribedInvocation usedAt;
 
-    public StubbedInvocationMatcher(MatchableInvocation invocation, Answer answer) {
+    public StubbedInvocationMatcher(Answer answer, MatchableInvocation invocation, Strictness strictness) {
         super(invocation.getInvocation(), invocation.getMatchers());
+        this.strictness = strictness;
         this.answers.add(answer);
     }
 
@@ -52,4 +55,9 @@
     public String toString() {
         return super.toString() + " stubbed with: " + answers;
     }
+
+    @Override
+    public Strictness getStrictness() {
+        return strictness;
+    }
 }
diff --git a/src/main/java/org/mockito/internal/stubbing/StubberImpl.java b/src/main/java/org/mockito/internal/stubbing/StubberImpl.java
index b18d05d..2172809 100644
--- a/src/main/java/org/mockito/internal/stubbing/StubberImpl.java
+++ b/src/main/java/org/mockito/internal/stubbing/StubberImpl.java
@@ -8,6 +8,7 @@
 import org.mockito.internal.stubbing.answers.Returns;
 import org.mockito.internal.stubbing.answers.ThrowsException;
 import org.mockito.internal.util.MockUtil;
+import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Answer;
 import org.mockito.stubbing.Stubber;
 
@@ -24,6 +25,12 @@
 
 public class StubberImpl implements Stubber {
 
+    private final Strictness strictness;
+
+    public StubberImpl(Strictness strictness) {
+        this.strictness = strictness;
+    }
+
     private final List<Answer<?>> answers = new LinkedList<Answer<?>>();
 
     @Override
@@ -36,7 +43,7 @@
             throw notAMockPassedToWhenMethod();
         }
 
-        MockUtil.getInvocationContainer(mock).setAnswersForStubbing(answers);
+        MockUtil.getInvocationContainer(mock).setAnswersForStubbing(answers, strictness);
 
         return mock;
     }
@@ -83,9 +90,9 @@
         Throwable e;
         try {
             e = newInstance(toBeThrown);
-        } catch (RuntimeException instanciationError) {
+        } catch (RuntimeException instantiationError) {
             mockingProgress().reset();
-            throw instanciationError;
+            throw instantiationError;
         }
         return doThrow(e);
     }
diff --git a/src/main/java/org/mockito/internal/stubbing/UnusedStubbingReporting.java b/src/main/java/org/mockito/internal/stubbing/UnusedStubbingReporting.java
new file mode 100644
index 0000000..6a96592
--- /dev/null
+++ b/src/main/java/org/mockito/internal/stubbing/UnusedStubbingReporting.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.stubbing;
+
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Stubbing;
+
+/**
+ * Helps determining if stubbing should be reported as unused
+ */
+public class UnusedStubbingReporting {
+
+    /**
+     * Decides if the stubbing should be reported as unused.
+     * Lenient stubbings are not reported as unused.
+     */
+    public static boolean shouldBeReported(Stubbing stubbing) {
+        return !stubbing.wasUsed() && stubbing.getStrictness() != Strictness.LENIENT;
+    }
+}
diff --git a/src/main/java/org/mockito/internal/stubbing/answers/ThrowsException.java b/src/main/java/org/mockito/internal/stubbing/answers/ThrowsException.java
index 037520f..502e359 100644
--- a/src/main/java/org/mockito/internal/stubbing/answers/ThrowsException.java
+++ b/src/main/java/org/mockito/internal/stubbing/answers/ThrowsException.java
@@ -14,23 +14,36 @@
 import static org.mockito.internal.exceptions.Reporter.cannotStubWithNullThrowable;
 import static org.mockito.internal.exceptions.Reporter.checkedExceptionInvalid;
 
+/**
+ * An answer that always throws the same throwable.
+ */
 public class ThrowsException implements Answer<Object>, ValidableAnswer, Serializable {
 
     private static final long serialVersionUID = 1128820328555183980L;
     private final Throwable throwable;
     private final ConditionalStackTraceFilter filter = new ConditionalStackTraceFilter();
 
+    /**
+     * Creates a new answer always throwing the given throwable. If it is null,
+     * {@linkplain ValidableAnswer#validateFor(InvocationOnMock) answer validation}
+     * will fail.
+     */
     public ThrowsException(Throwable throwable) {
         this.throwable = throwable;
     }
 
     public Object answer(InvocationOnMock invocation) throws Throwable {
+        if (throwable == null) {
+            throw new IllegalStateException("throwable is null: " +
+                "you shall not call #answer if #validateFor fails!");
+        }
         if (MockUtil.isMock(throwable)) {
             throw throwable;
         }
         Throwable t = throwable.fillInStackTrace();
 
         if (t == null) {
+            //Custom exceptions sometimes return null, see #866
             throw throwable;
         }
         filter.filter(t);
diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java
index 3b2cb3d..3909ff0 100644
--- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java
+++ b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsDeepStubs.java
@@ -61,7 +61,7 @@
 
         // matches invocation for verification
         // TODO why don't we do container.findAnswer here?
-        for (Stubbing stubbing : container.getStubbedInvocations()) {
+        for (Stubbing stubbing : container.getStubbingsDescending()) {
             if (container.getInvocationForStubbing().matches(stubbing.getInvocation())) {
                 return stubbing.answer(invocation);
             }
@@ -118,7 +118,7 @@
 
     private StubbedInvocationMatcher recordDeepStubAnswer(final Object mock, InvocationContainerImpl container) {
         DeeplyStubbedAnswer answer = new DeeplyStubbedAnswer(mock);
-        return container.addAnswer(answer, false);
+        return container.addAnswer(answer, false, null);
     }
 
     protected GenericMetadataSupport actualParameterizedType(Object mock) {
diff --git a/src/main/java/org/mockito/internal/util/DefaultMockingDetails.java b/src/main/java/org/mockito/internal/util/DefaultMockingDetails.java
index 0c3669c..4f739cd 100644
--- a/src/main/java/org/mockito/internal/util/DefaultMockingDetails.java
+++ b/src/main/java/org/mockito/internal/util/DefaultMockingDetails.java
@@ -8,15 +8,12 @@
 import org.mockito.exceptions.misusing.NotAMockException;
 import org.mockito.internal.debugging.InvocationsPrinter;
 import org.mockito.internal.stubbing.InvocationContainerImpl;
-import org.mockito.internal.stubbing.StubbingComparator;
 import org.mockito.invocation.Invocation;
 import org.mockito.invocation.MockHandler;
 import org.mockito.mock.MockCreationSettings;
 import org.mockito.stubbing.Stubbing;
 
 import java.util.Collection;
-import java.util.List;
-import java.util.TreeSet;
 
 /**
  * Class to inspect any object, and identify whether a particular object is either a mock or a spy.  This is
@@ -57,10 +54,7 @@
 
     @Override
     public Collection<Stubbing> getStubbings() {
-        List<? extends Stubbing> stubbings = getInvocationContainer().getStubbedInvocations();
-        TreeSet<Stubbing> out = new TreeSet<Stubbing>(new StubbingComparator());
-        out.addAll(stubbings);
-        return out;
+        return getInvocationContainer().getStubbingsAscending();
     }
 
     @Override
diff --git a/src/main/java/org/mockito/internal/util/Primitives.java b/src/main/java/org/mockito/internal/util/Primitives.java
index 4d813e3..80dd0af 100644
--- a/src/main/java/org/mockito/internal/util/Primitives.java
+++ b/src/main/java/org/mockito/internal/util/Primitives.java
@@ -44,7 +44,7 @@
 
     public static boolean isAssignableFromWrapper(Class<?> valueClass, Class<?> referenceType) {
         if(isPrimitiveOrWrapper(valueClass) && isPrimitiveOrWrapper(referenceType)) {
-            return Primitives.primitiveTypeOf(valueClass).isAssignableFrom(referenceType);
+            return Primitives.primitiveTypeOf(valueClass).isAssignableFrom(Primitives.primitiveTypeOf(referenceType));
         }
         return false;
     }
diff --git a/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java b/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
index b411a73..487d223 100644
--- a/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
+++ b/src/main/java/org/mockito/internal/util/concurrent/WeakConcurrentMap.java
@@ -50,6 +50,7 @@
      * @param key The key of the entry.
      * @return The value of the entry or the default value if it did not exist.
      */
+    @SuppressWarnings("CollectionIncompatibleType")
     public V get(K key) {
         if (key == null) throw new NullPointerException();
         V value = target.get(new LatentKey<K>(key));
@@ -69,6 +70,7 @@
      * @param key The key of the entry.
      * @return {@code true} if the key already defines a value.
      */
+    @SuppressWarnings("CollectionIncompatibleType")
     public boolean containsKey(K key) {
         if (key == null) throw new NullPointerException();
         return target.containsKey(new LatentKey<K>(key));
@@ -88,6 +90,7 @@
      * @param key The key of the entry.
      * @return The removed entry or {@code null} if it does not exist.
      */
+    @SuppressWarnings("CollectionIncompatibleType")
     public V remove(K key) {
         if (key == null) throw new NullPointerException();
         return target.remove(new LatentKey<K>(key));
diff --git a/src/main/java/org/mockito/internal/verification/checkers/AtLeastXNumberOfInvocationsChecker.java b/src/main/java/org/mockito/internal/verification/checkers/AtLeastXNumberOfInvocationsChecker.java
index 36e35a3..d0eb0b5 100644
--- a/src/main/java/org/mockito/internal/verification/checkers/AtLeastXNumberOfInvocationsChecker.java
+++ b/src/main/java/org/mockito/internal/verification/checkers/AtLeastXNumberOfInvocationsChecker.java
@@ -17,7 +17,7 @@
 import static org.mockito.internal.invocation.InvocationMarker.markVerifiedInOrder;
 import static org.mockito.internal.invocation.InvocationsFinder.findAllMatchingUnverifiedChunks;
 import static org.mockito.internal.invocation.InvocationsFinder.findInvocations;
-import static org.mockito.internal.invocation.InvocationsFinder.getLastLocation;
+import static org.mockito.internal.invocation.InvocationsFinder.getAllLocations;
 
 public class AtLeastXNumberOfInvocationsChecker {
 
@@ -26,8 +26,8 @@
 
         int actualCount = actualInvocations.size();
         if (wantedCount > actualCount) {
-            Location lastLocation = getLastLocation(actualInvocations);
-            throw tooLittleActualInvocations(new AtLeastDiscrepancy(wantedCount, actualCount), wanted, lastLocation);
+            List<Location> allLocations = getAllLocations(actualInvocations);
+            throw tooLittleActualInvocations(new AtLeastDiscrepancy(wantedCount, actualCount), wanted, allLocations);
         }
 
         markVerified(actualInvocations, wanted);
@@ -39,8 +39,8 @@
         int actualCount = chunk.size();
 
         if (wantedCount > actualCount) {
-            Location lastLocation = getLastLocation(chunk);
-            throw tooLittleActualInvocationsInOrder(new AtLeastDiscrepancy(wantedCount, actualCount), wanted, lastLocation);
+            List<Location> allLocations = getAllLocations(chunk);
+            throw tooLittleActualInvocationsInOrder(new AtLeastDiscrepancy(wantedCount, actualCount), wanted, allLocations);
         }
 
         markVerifiedInOrder(chunk, wanted, orderingContext);
diff --git a/src/main/java/org/mockito/internal/verification/checkers/NumberOfInvocationsChecker.java b/src/main/java/org/mockito/internal/verification/checkers/NumberOfInvocationsChecker.java
index 3fa340f..1dfc2f1 100644
--- a/src/main/java/org/mockito/internal/verification/checkers/NumberOfInvocationsChecker.java
+++ b/src/main/java/org/mockito/internal/verification/checkers/NumberOfInvocationsChecker.java
@@ -5,6 +5,7 @@
 
 package org.mockito.internal.verification.checkers;
 
+import java.util.Arrays;
 import java.util.List;
 import org.mockito.internal.reporting.Discrepancy;
 import org.mockito.internal.verification.api.InOrderContext;
@@ -22,7 +23,7 @@
 import static org.mockito.internal.invocation.InvocationsFinder.findFirstMatchingUnverifiedInvocation;
 import static org.mockito.internal.invocation.InvocationsFinder.findInvocations;
 import static org.mockito.internal.invocation.InvocationsFinder.findMatchingChunk;
-import static org.mockito.internal.invocation.InvocationsFinder.getLastLocation;
+import static org.mockito.internal.invocation.InvocationsFinder.getAllLocations;
 
 public class NumberOfInvocationsChecker {
 
@@ -34,16 +35,14 @@
 
         int actualCount = actualInvocations.size();
         if (wantedCount > actualCount) {
-            Location lastInvocation = getLastLocation(actualInvocations);
-            throw tooLittleActualInvocations(new Discrepancy(wantedCount, actualCount), wanted, lastInvocation);
+            List<Location> allLocations = getAllLocations(actualInvocations);
+            throw tooLittleActualInvocations(new Discrepancy(wantedCount, actualCount), wanted, allLocations);
         }
         if (wantedCount == 0 && actualCount > 0) {
-            Location firstUndesired = actualInvocations.get(wantedCount).getLocation();
-            throw neverWantedButInvoked(wanted, firstUndesired);
+            throw neverWantedButInvoked(wanted, getAllLocations(actualInvocations));
         }
         if (wantedCount < actualCount) {
-            Location firstUndesired = actualInvocations.get(wantedCount).getLocation();
-            throw tooManyActualInvocations(wantedCount, actualCount, wanted, firstUndesired);
+            throw tooManyActualInvocations(wantedCount, actualCount, wanted, getAllLocations(actualInvocations));
         }
 
         markVerified(actualInvocations, wanted);
@@ -55,12 +54,11 @@
         int actualCount = chunk.size();
 
         if (wantedCount > actualCount) {
-            Location lastInvocation = getLastLocation(chunk);
-            throw tooLittleActualInvocationsInOrder(new Discrepancy(wantedCount, actualCount), wanted, lastInvocation);
+            List<Location> allLocations = getAllLocations(chunk);
+            throw tooLittleActualInvocationsInOrder(new Discrepancy(wantedCount, actualCount), wanted, allLocations);
         }
         if (wantedCount < actualCount) {
-            Location firstUndesired = chunk.get(wantedCount).getLocation();
-            throw tooManyActualInvocationsInOrder(wantedCount, actualCount, wanted, firstUndesired);
+            throw tooManyActualInvocationsInOrder(wantedCount, actualCount, wanted, getAllLocations(chunk));
         }
 
         markVerifiedInOrder(chunk, wanted, context);
@@ -72,7 +70,7 @@
         while( actualCount < wantedCount ){
             Invocation next = findFirstMatchingUnverifiedInvocation(invocations, wanted, context );
             if( next == null ){
-                throw tooLittleActualInvocationsInOrder(new Discrepancy(wantedCount, actualCount), wanted, lastLocation );
+                throw tooLittleActualInvocationsInOrder(new Discrepancy(wantedCount, actualCount), wanted, Arrays.asList(lastLocation));
             }
             markVerified( next, wanted );
             context.markVerified( next );
diff --git a/src/main/java/org/mockito/junit/MockitoJUnit.java b/src/main/java/org/mockito/junit/MockitoJUnit.java
index 2f8b65f..da9428b 100644
--- a/src/main/java/org/mockito/junit/MockitoJUnit.java
+++ b/src/main/java/org/mockito/junit/MockitoJUnit.java
@@ -5,13 +5,18 @@
 package org.mockito.junit;
 
 import org.mockito.Incubating;
-import org.mockito.quality.Strictness;
 import org.mockito.internal.junit.JUnitRule;
 import org.mockito.internal.junit.VerificationCollectorImpl;
 import org.mockito.internal.util.ConsoleMockitoLogger;
+import org.mockito.quality.Strictness;
 
 /**
- * The JUnit rule can be used instead of {@link MockitoJUnitRunner}. See {@link MockitoRule}.
+ * Mockito supports JUnit via:
+ * <li>
+ *     <ul>JUnit Rules - see {@link MockitoRule}</ul>
+ *     <ul>JUnit runners - see {@link MockitoJUnitRunner}</ul>
+ *     <ul><a href="http://javadoc.io/page/org.mockito/mockito-junit-jupiter/latest/org/mockito/junit/jupiter/MockitoExtension.html">JUnit Jupiter extension</a></ul>
+ * </li>
  *
  * @since 1.10.17
  */
diff --git a/src/main/java/org/mockito/junit/MockitoRule.java b/src/main/java/org/mockito/junit/MockitoRule.java
index 296faa7..561fff7 100644
--- a/src/main/java/org/mockito/junit/MockitoRule.java
+++ b/src/main/java/org/mockito/junit/MockitoRule.java
@@ -6,6 +6,8 @@
 
 import org.junit.rules.MethodRule;
 import org.mockito.Incubating;
+import org.mockito.MockSettings;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.MockitoSession;
 import org.mockito.quality.MockitoHint;
@@ -104,7 +106,7 @@
      * The strictness, especially "strict stubs" ({@link Strictness#STRICT_STUBS})
      * helps debugging and keeping tests clean.
      * It's a new feature introduced in Mockito 2.3.
-     * Other levels of strictness - "Warn" - current default ({@link Strictness#WARN})
+     * Other levels of strictness - "warn" - ({@link Strictness#WARN})
      * and "lenient" ({@link MockitoRule#silent()}) strictness were already present in Mockito 2.1.0.
      * Version 2.3.0 introduces "strict stubs" ({@link Strictness#STRICT_STUBS}).
      *
@@ -115,21 +117,12 @@
      * }
      * </code></pre>
      *
-     * How strictness level influences the behavior of JUnit rule:
-     * <ol>
-     *     <li>{@link Strictness#LENIENT} - equivalent of {@link MockitoRule#silent()} -
-     *      no added behavior. The default of Mockito 1.x </li>
-     *     <li>{@link Strictness#WARN} - helps keeping tests clean and with debuggability.
-     *     Reports console warnings about unused stubs
-     *     and stubbing argument mismatches (see {@link MockitoHint}).
-     *     The default of Mockito 2.x</li>
-     *     <li>{@link Strictness#STRICT_STUBS} - ensures clean tests,
-     *     reduces test code duplication, improves debuggability.
-     *     See the details in the Javadoc for {@link Strictness#STRICT_STUBS}.
-     * </ol>
-     *
+     * See Javadoc for {@link Strictness} to learn how strictness influences the behavior of the JUnit rule.
+     * See {@link Strictness#STRICT_STUBS} to learn why is it recommended to use "strict stubbing".
+     * <p>
      * It is possible to tweak the strictness per test method.
      * Why would you need it? See the use cases in Javadoc for {@link PotentialStubbingProblem} class.
+     * In order to tweak strictness per stubbing see {@link Mockito#lenient()}, per mock see {@link MockSettings#lenient()}.
      *
      * <pre class="code"><code class="java">
      * public class ExampleTest {
@@ -146,7 +139,7 @@
      * }
      * </code></pre>
      *
-     * "Strict stubs" are tentatively planned to be the default for Mockito v3</li>
+     * "Strict stubs" are planned to be the default for Mockito v3</li>
      * We are very eager to hear feedback about "strict stubbing" feature, let us know by commenting on GitHub
      * <a href="https://github.com/mockito/mockito/issues/769">issue 769</a>.
      * Strict stubbing is an attempt to improve testability and productivity with Mockito. Tell us what you think!
diff --git a/src/main/java/org/mockito/mock/MockCreationSettings.java b/src/main/java/org/mockito/mock/MockCreationSettings.java
index b58daf0..7e74be8 100644
--- a/src/main/java/org/mockito/mock/MockCreationSettings.java
+++ b/src/main/java/org/mockito/mock/MockCreationSettings.java
@@ -6,9 +6,11 @@
 package org.mockito.mock;
 
 import org.mockito.Incubating;
+import org.mockito.MockSettings;
 import org.mockito.NotExtensible;
 import org.mockito.listeners.InvocationListener;
 import org.mockito.listeners.VerificationStartedListener;
+import org.mockito.quality.Strictness;
 import org.mockito.stubbing.Answer;
 
 import java.util.List;
@@ -109,4 +111,13 @@
      */
     @Incubating
     Object getOuterClassInstance();
+
+    /**
+     * Informs if the mock was created with "lenient" strictness, e.g. having {@link Strictness#LENIENT} characteristic.
+     * For more information about using mocks with lenient strictness, see {@link MockSettings#lenient()}.
+     *
+     * @since 2.20.0
+     */
+    @Incubating
+    boolean isLenient();
 }
diff --git a/src/main/java/org/mockito/quality/MockitoHint.java b/src/main/java/org/mockito/quality/MockitoHint.java
index d752159..f261ac1 100644
--- a/src/main/java/org/mockito/quality/MockitoHint.java
+++ b/src/main/java/org/mockito/quality/MockitoHint.java
@@ -8,10 +8,13 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 /**
+ * Stubbing hints were introduced in Mockito 2 in order to improve debuggability while keeping backwards compatibility.
+ * As Mockito 2 evolved, hints are replaced by  "strict stubbing" API ({@link Strictness}).
+ * In Mockito 3 we won't be needing hints because {@link Strictness#STRICT_STUBS} will be the default for all mocks.
+ * <p>
+ * Why hints?
  * To improve productivity when writing Java tests
  * stubbing hints and warnings are printed to standard output.
- * See also "strict stubbing" API ({@link Strictness})
- * which drives cleaner tests and productivity more effectively than Mockito hints.
  * <p>
  * Hints contain clickable links that take you right to the line of code that contains a possible problem.
  * Those are hints - they not necessarily indicate real problems 100% of the time.
diff --git a/src/main/java/org/mockito/quality/Strictness.java b/src/main/java/org/mockito/quality/Strictness.java
index c9da8d3..ea9fed8 100644
--- a/src/main/java/org/mockito/quality/Strictness.java
+++ b/src/main/java/org/mockito/quality/Strictness.java
@@ -9,31 +9,31 @@
 import org.mockito.exceptions.misusing.PotentialStubbingProblem;
 import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
 import org.mockito.internal.junit.JUnitRule;
+import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.junit.MockitoRule;
 
 /**
- * Configures the "strictness" of Mockito during a mocking session.
- * A session typically maps to a single test method invocation.
- * {@code Strictness} drives cleaner tests and better productivity.
- * The easiest way to leverage enhanced {@code Strictness} is using
- * Mockito's JUnit support ({@link MockitoRule} or {@link MockitoJUnitRunner}).
- * If you cannot use JUnit support {@link MockitoSession} is the way to go.
+ * Configures the "strictness" of Mockito, affecting the behavior of stubbings and verification.
+ * "Strict stubbing" is a new feature in Mockito 2 that drives cleaner tests and better productivity.
+ * The easiest way to leverage it is via Mockito's JUnit support ({@link MockitoJUnit}) or Mockito Session ({@link MockitoSession}).
  * <p>
- * How strictness level influences the behavior of the test (mocking session)?
+ * How strictness influences the behavior of the test?
  * <ol>
- *     <li>{@link Strictness#LENIENT} - no added behavior.
- *       The default of Mockito 1.x.
- *       Recommended only if you cannot use {@link #STRICT_STUBS} nor {@link #WARN}.</li>
- *     <li>{@link Strictness#WARN} - helps keeping tests clean and improves debuggability.
- *       Reports console warnings about unused stubs
- *       and stubbing argument mismatch (see {@link org.mockito.quality.MockitoHint}).
- *       The default behavior of Mockito 2.x when {@link JUnitRule} or {@link MockitoJUnitRunner} are used.</li>
- *       Recommended if you cannot use {@link #STRICT_STUBS}.
  *     <li>{@link Strictness#STRICT_STUBS} - ensures clean tests, reduces test code duplication, improves debuggability.
  *       Best combination of flexibility and productivity. Highly recommended.
  *       Planned as default for Mockito v3.
- *       See {@link #STRICT_STUBS} for the details.
+ *       Enable it via {@link MockitoRule}, {@link MockitoJUnitRunner} or {@link MockitoSession}.
+ *       See {@link #STRICT_STUBS} for the details.</li>
+ *     <li>{@link Strictness#LENIENT} - no added behavior.
+ *       The default of Mockito 1.x.
+ *       Recommended only if you cannot use {@link #STRICT_STUBS}</li>
+ *     <li>{@link Strictness#WARN} - cleaner tests but only if you read the console output.
+ *       Reports console warnings about unused stubs
+ *       and stubbing argument mismatch (see {@link org.mockito.quality.MockitoHint}).
+ *       The default behavior of Mockito 2.x when {@link JUnitRule} or {@link MockitoJUnitRunner} are used.
+ *       Recommended if you cannot use {@link #STRICT_STUBS}.
+ *       Introduced originally with Mockito 2 because console warnings was the only compatible way of adding such feature.</li>
  * </ol>
  *
  * @since 2.3.0
@@ -43,7 +43,7 @@
 
     /**
      * No extra strictness. Mockito 1.x behavior.
-     * Recommended only if you cannot use {@link #STRICT_STUBS} nor {@link #WARN}.
+     * Recommended only if you cannot use {@link #STRICT_STUBS}.
      * <p>
      * For more information see {@link Strictness}.
      *
@@ -53,10 +53,10 @@
     LENIENT,
 
     /**
-     * Helps keeping tests clean and improves debuggability.
+     * Helps keeping tests clean and improves debuggability only if you read the console output.
      * Extra warnings emitted to the console, see {@link MockitoHint}.
      * Default Mockito 2.x behavior.
-     * Recommended if you cannot use {@link #STRICT_STUBS}.
+     * Recommended only if you cannot use {@link #STRICT_STUBS} because console output is ignored most of the time.
      * <p>
      * For more information see {@link Strictness}.
      *
@@ -70,6 +70,7 @@
      * Offers best combination of flexibility and productivity.
      * Highly recommended.
      * Planned as default for Mockito v3.
+     * Enable it via our JUnit support ({@link MockitoJUnit}) or {@link MockitoSession}.
      * <p>
      * Adds following behavior:
      *  <ul>
@@ -80,8 +81,7 @@
      *      <li>Cleaner, more DRY tests ("Don't Repeat Yourself"):
      *          If you use {@link org.mockito.Mockito#verifyNoMoreInteractions(Object...)}
      *          you no longer need to explicitly verify stubbed invocations.
-     *          They are automatically verified for you. However if you have more invocations,
-     *          the test won't fail since it won't check that there are no more interactions on that stub.</li>
+     *          They are automatically verified for you.</li>
      *  </ul>
      *
      * For more information see {@link Strictness}.
diff --git a/src/main/java/org/mockito/session/MockitoSessionBuilder.java b/src/main/java/org/mockito/session/MockitoSessionBuilder.java
index 474b7f9..b3a758b 100644
--- a/src/main/java/org/mockito/session/MockitoSessionBuilder.java
+++ b/src/main/java/org/mockito/session/MockitoSessionBuilder.java
@@ -47,7 +47,7 @@
      * like {@link org.mockito.Mock}.
      * <p>
      * In most scenarios, you only need to init mocks on a single test class instance.
-     * This method is useful for advanced framework integrations (like JUnit5), when a test uses multiple, e.g. nested, test class instances.
+     * This method is useful for advanced framework integrations (like JUnit Jupiter), when a test uses multiple, e.g. nested, test class instances.
      * <p>
      * This method calls {@link #initMocks(Object)} for each passed test class instance.
      *
diff --git a/src/main/java/org/mockito/stubbing/BaseStubber.java b/src/main/java/org/mockito/stubbing/BaseStubber.java
new file mode 100644
index 0000000..8c31928
--- /dev/null
+++ b/src/main/java/org/mockito/stubbing/BaseStubber.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.stubbing;
+
+import org.mockito.Mockito;
+import org.mockito.NotExtensible;
+
+/**
+ * Base interface for stubbing consecutive method calls with {@link Mockito#doReturn(Object)} syntax.
+ * This interface is needed so that we can reuse the same hierarchy in subinterfaces.
+ *
+ * @since 2.20.0
+ */
+@NotExtensible
+public interface BaseStubber {
+
+    /**
+     * Use it for stubbing consecutive calls in {@link Mockito#doThrow(Throwable[])} style:
+     * <pre class="code"><code class="java">
+     *   doThrow(new RuntimeException("one")).
+     *   doThrow(new RuntimeException("two"))
+     *       .when(mock).someVoidMethod();
+     * </code></pre>
+     * See javadoc for {@link Mockito#doThrow(Throwable[])}
+     *
+     * @param toBeThrown to be thrown when the stubbed method is called
+     * @return stubber - to select a method for stubbing
+     */
+    Stubber doThrow(Throwable... toBeThrown);
+
+    /**
+     * Use it for stubbing consecutive calls in {@link Mockito#doThrow(Class)} style:
+     * <pre class="code"><code class="java">
+     *   doThrow(RuntimeException.class).
+     *   doThrow(IllegalArgumentException.class)
+     *       .when(mock).someVoidMethod();
+     * </code></pre>
+     * See javadoc for {@link Mockito#doThrow(Class)}
+     *
+     * @param toBeThrown exception class to be thrown when the stubbed method is called
+     * @return stubber - to select a method for stubbing
+     *
+     * @since 2.1.0
+     */
+    Stubber doThrow(Class<? extends Throwable> toBeThrown);
+
+    /**
+     * Use it for stubbing consecutive calls in {@link Mockito#doThrow(Class)} style:
+     * <pre class="code"><code class="java">
+     *   doThrow(RuntimeException.class).
+     *   doThrow(IllegalArgumentException.class)
+     *       .when(mock).someVoidMethod();
+     * </code></pre>
+     * See javadoc for {@link Mockito#doThrow(Class)}
+     *
+     * @param toBeThrown exception class to be thrown when the stubbed method is called
+     * @param nextToBeThrown exception class next to be thrown when the stubbed method is called
+     * @return stubber - to select a method for stubbing
+     *
+     * @since 2.1.0
+     */
+    // Additional method helps users of JDK7+ to hide heap pollution / unchecked generics array creation
+    @SuppressWarnings ({"unchecked", "varargs"})
+    Stubber doThrow(Class<? extends Throwable> toBeThrown, Class<? extends Throwable>... nextToBeThrown);
+
+    /**
+     * Use it for stubbing consecutive calls in {@link Mockito#doAnswer(Answer)} style:
+     * <pre class="code"><code class="java">
+     *   doAnswer(answerOne).
+     *   doAnswer(answerTwo)
+     *       .when(mock).someVoidMethod();
+     * </code></pre>
+     * See javadoc for {@link Mockito#doAnswer(Answer)}
+     *
+     * @param answer to answer when the stubbed method is called
+     * @return stubber - to select a method for stubbing
+     */
+    Stubber doAnswer(Answer answer);
+
+    /**
+     * Use it for stubbing consecutive calls in {@link Mockito#doNothing()} style:
+     * <pre class="code"><code class="java">
+     *   doNothing().
+     *   doThrow(new RuntimeException("two"))
+     *       .when(mock).someVoidMethod();
+     * </code></pre>
+     * See javadoc for {@link Mockito#doNothing()}
+     *
+     * @return stubber - to select a method for stubbing
+     */
+    Stubber doNothing();
+
+    /**
+     * Use it for stubbing consecutive calls in {@link Mockito#doReturn(Object)} style.
+     * <p>
+     * See javadoc for {@link Mockito#doReturn(Object)}
+     *
+     * @param toBeReturned to be returned when the stubbed method is called
+     * @return stubber - to select a method for stubbing
+     */
+    Stubber doReturn(Object toBeReturned);
+
+    /**
+     * Use it for stubbing consecutive calls in {@link Mockito#doReturn(Object)} style.
+     * <p>
+     * See javadoc for {@link Mockito#doReturn(Object, Object...)}
+     *
+     * @param toBeReturned to be returned when the stubbed method is called
+     * @param nextToBeReturned to be returned in consecutive calls when the stubbed method is called
+     * @return stubber - to select a method for stubbing
+     */
+    @SuppressWarnings({"unchecked", "varargs"})
+    Stubber doReturn(Object toBeReturned, Object... nextToBeReturned);
+
+    /**
+     * Use it for stubbing consecutive calls in {@link Mockito#doCallRealMethod()} style.
+     * <p>
+     * See javadoc for {@link Mockito#doCallRealMethod()}
+     *
+     * @return stubber - to select a method for stubbing
+     */
+    Stubber doCallRealMethod();
+}
diff --git a/src/main/java/org/mockito/stubbing/LenientStubber.java b/src/main/java/org/mockito/stubbing/LenientStubber.java
new file mode 100644
index 0000000..9088399
--- /dev/null
+++ b/src/main/java/org/mockito/stubbing/LenientStubber.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.stubbing;
+
+import org.mockito.CheckReturnValue;
+import org.mockito.Mockito;
+import org.mockito.NotExtensible;
+
+/**
+ * Used for declaring optional stubbings with {@link Mockito#lenient()}
+ *
+ * @since 2.20.0
+ */
+@NotExtensible
+public interface LenientStubber extends BaseStubber {
+
+    /**
+     * Allows declaring the method to stub. See {@link Mockito#when(Object)}.
+     * Needed for classic stubbing with when().then()
+     *
+     * @since 2.20.0
+     */
+    @CheckReturnValue
+    <T> OngoingStubbing<T> when(T methodCall);
+}
diff --git a/src/main/java/org/mockito/stubbing/Stubber.java b/src/main/java/org/mockito/stubbing/Stubber.java
index b7507a7..5de954b 100644
--- a/src/main/java/org/mockito/stubbing/Stubber.java
+++ b/src/main/java/org/mockito/stubbing/Stubber.java
@@ -5,6 +5,7 @@
 package org.mockito.stubbing;
 
 import org.mockito.Mockito;
+import org.mockito.NotExtensible;
 
 /**
  * Allows to choose a method when stubbing in doThrow()|doAnswer()|doNothing()|doReturn() style
@@ -39,7 +40,8 @@
  * See examples in javadoc for {@link Mockito}
  */
 @SuppressWarnings("unchecked")
-public interface Stubber {
+@NotExtensible
+public interface Stubber extends BaseStubber {
 
     /**
      * Allows to choose a method when stubbing in doThrow()|doAnswer()|doNothing()|doReturn() style
@@ -70,111 +72,4 @@
      * @return select method for stubbing
      */
     <T> T when(T mock);
-
-    /**
-     * Use it for stubbing consecutive calls in {@link Mockito#doThrow(Throwable[])} style:
-     * <pre class="code"><code class="java">
-     *   doThrow(new RuntimeException("one")).
-     *   doThrow(new RuntimeException("two"))
-     *       .when(mock).someVoidMethod();
-     * </code></pre>
-     * See javadoc for {@link Mockito#doThrow(Throwable[])}
-     *
-     * @param toBeThrown to be thrown when the stubbed method is called
-     * @return stubber - to select a method for stubbing
-     */
-    Stubber doThrow(Throwable... toBeThrown);
-
-    /**
-     * Use it for stubbing consecutive calls in {@link Mockito#doThrow(Class)} style:
-     * <pre class="code"><code class="java">
-     *   doThrow(RuntimeException.class).
-     *   doThrow(IllegalArgumentException.class)
-     *       .when(mock).someVoidMethod();
-     * </code></pre>
-     * See javadoc for {@link Mockito#doThrow(Class)}
-     *
-     * @param toBeThrown exception class to be thrown when the stubbed method is called
-     * @return stubber - to select a method for stubbing
-     *
-     * @since 2.1.0
-     */
-    Stubber doThrow(Class<? extends Throwable> toBeThrown);
-
-    /**
-     * Use it for stubbing consecutive calls in {@link Mockito#doThrow(Class)} style:
-     * <pre class="code"><code class="java">
-     *   doThrow(RuntimeException.class).
-     *   doThrow(IllegalArgumentException.class)
-     *       .when(mock).someVoidMethod();
-     * </code></pre>
-     * See javadoc for {@link Mockito#doThrow(Class)}
-     *
-     * @param toBeThrown exception class to be thrown when the stubbed method is called
-     * @param nextToBeThrown exception class next to be thrown when the stubbed method is called
-     * @return stubber - to select a method for stubbing
-     *
-     * @since 2.1.0
-     */
-    // Additional method helps users of JDK7+ to hide heap pollution / unchecked generics array creation
-    @SuppressWarnings ({"unchecked", "varargs"})
-    Stubber doThrow(Class<? extends Throwable> toBeThrown, Class<? extends Throwable>... nextToBeThrown);
-
-    /**
-     * Use it for stubbing consecutive calls in {@link Mockito#doAnswer(Answer)} style:
-     * <pre class="code"><code class="java">
-     *   doAnswer(answerOne).
-     *   doAnswer(answerTwo)
-     *       .when(mock).someVoidMethod();
-     * </code></pre>
-     * See javadoc for {@link Mockito#doAnswer(Answer)}
-     *
-     * @param answer to answer when the stubbed method is called
-     * @return stubber - to select a method for stubbing
-     */
-    Stubber doAnswer(Answer answer);
-
-    /**
-     * Use it for stubbing consecutive calls in {@link Mockito#doNothing()} style:
-     * <pre class="code"><code class="java">
-     *   doNothing().
-     *   doThrow(new RuntimeException("two"))
-     *       .when(mock).someVoidMethod();
-     * </code></pre>
-     * See javadoc for {@link Mockito#doNothing()}
-     *
-     * @return stubber - to select a method for stubbing
-     */
-    Stubber doNothing();
-
-    /**
-     * Use it for stubbing consecutive calls in {@link Mockito#doReturn(Object)} style.
-     * <p>
-     * See javadoc for {@link Mockito#doReturn(Object)}
-     *
-     * @param toBeReturned to be returned when the stubbed method is called
-     * @return stubber - to select a method for stubbing
-     */
-    Stubber doReturn(Object toBeReturned);
-
-    /**
-     * Use it for stubbing consecutive calls in {@link Mockito#doReturn(Object)} style.
-     * <p>
-     * See javadoc for {@link Mockito#doReturn(Object, Object...)}
-     *
-     * @param toBeReturned to be returned when the stubbed method is called
-     * @param nextToBeReturned to be returned in consecutive calls when the stubbed method is called
-     * @return stubber - to select a method for stubbing
-     */
-    @SuppressWarnings({"unchecked", "varargs"})
-    Stubber doReturn(Object toBeReturned, Object... nextToBeReturned);
-
-    /**
-     * Use it for stubbing consecutive calls in {@link Mockito#doCallRealMethod()} style.
-     * <p>
-     * See javadoc for {@link Mockito#doCallRealMethod()}
-     *
-     * @return stubber - to select a method for stubbing
-     */
-    Stubber doCallRealMethod();
 }
diff --git a/src/main/java/org/mockito/stubbing/Stubbing.java b/src/main/java/org/mockito/stubbing/Stubbing.java
index 09856fb..cba0917 100644
--- a/src/main/java/org/mockito/stubbing/Stubbing.java
+++ b/src/main/java/org/mockito/stubbing/Stubbing.java
@@ -4,9 +4,12 @@
  */
 package org.mockito.stubbing;
 
+import org.mockito.Incubating;
 import org.mockito.MockingDetails;
+import org.mockito.Mockito;
 import org.mockito.NotExtensible;
 import org.mockito.invocation.Invocation;
+import org.mockito.quality.Strictness;
 
 /**
  * Stubbing declared on the mock object.
@@ -50,4 +53,13 @@
      * @since 2.2.3
      */
     boolean wasUsed();
+
+    /**
+     * Informs about the {@link Strictness} level of this stubbing.
+     * For more information about setting strictness for stubbings see {@link Mockito#lenient()}.
+     *
+     * @since 2.20.0
+     */
+    @Incubating
+    Strictness getStrictness();
 }
diff --git a/src/test/java/org/mockito/AnnotationsAreCopiedFromMockedTypeTest.java b/src/test/java/org/mockito/AnnotationsAreCopiedFromMockedTypeTest.java
index 7670183..1d9dfbb 100644
--- a/src/test/java/org/mockito/AnnotationsAreCopiedFromMockedTypeTest.java
+++ b/src/test/java/org/mockito/AnnotationsAreCopiedFromMockedTypeTest.java
@@ -63,7 +63,7 @@
             @SuppressWarnings("unchecked")
             public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
                 for (Annotation firstParamAnnotation : firstParamAnnotations) {
-                    if (annotationClass.isAssignableFrom(firstParamAnnotation.getClass())) {
+                    if (annotationClass.isAssignableFrom(firstParamAnnotation.annotationType())) {
                         return (T) firstParamAnnotation;
                     }
                 }
diff --git a/src/test/java/org/mockito/MockitoTest.java b/src/test/java/org/mockito/MockitoTest.java
index 3b96aff..ca8c4d4 100644
--- a/src/test/java/org/mockito/MockitoTest.java
+++ b/src/test/java/org/mockito/MockitoTest.java
@@ -25,11 +25,13 @@
         assertThat(mockingProgress().pullOngoingStubbing()).isNull();
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test(expected=NotAMockException.class)
     public void shouldValidateMockWhenVerifying() {
         Mockito.verify("notMock");
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test(expected=NotAMockException.class)
     public void shouldValidateMockWhenVerifyingWithExpectedNumberOfInvocations() {
         Mockito.verify("notMock", times(19));
@@ -45,6 +47,7 @@
         Mockito.verifyZeroInteractions("notMock");
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test(expected=NotAMockException.class)
     public void shouldValidateMockWhenCreatingInOrderObject() {
         Mockito.inOrder("notMock");
diff --git a/src/test/java/org/mockito/StaticMockingExperimentTest.java b/src/test/java/org/mockito/StaticMockingExperimentTest.java
index bb5e225..cc8a598 100644
--- a/src/test/java/org/mockito/StaticMockingExperimentTest.java
+++ b/src/test/java/org/mockito/StaticMockingExperimentTest.java
@@ -54,6 +54,7 @@
         staticMethod = Foo.class.getDeclaredMethod("staticMethod", String.class);
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void verify_static_method() throws Throwable {
         //register staticMethod call on mock
@@ -81,6 +82,7 @@
         handler.handle(differentArg);
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void verification_failure_static_method() throws Throwable {
         //register staticMethod call on mock
@@ -178,6 +180,7 @@
         assertEquals(null, result2);
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void verifying_new() throws Throwable {
         Constructor<Foo> ctr = Foo.class.getConstructor(String.class);
diff --git a/src/test/java/org/mockito/internal/InvalidStateDetectionTest.java b/src/test/java/org/mockito/internal/InvalidStateDetectionTest.java
index c243e92..6baae82 100644
--- a/src/test/java/org/mockito/internal/InvalidStateDetectionTest.java
+++ b/src/test/java/org/mockito/internal/InvalidStateDetectionTest.java
@@ -46,6 +46,7 @@
         super.resetState();
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldDetectUnfinishedStubbing() {
         when(mock.simpleMethod());
@@ -70,6 +71,7 @@
         detectsAndCleansUp(new OnDoAnswer(), UnfinishedStubbingException.class);
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldDetectUnfinishedDoAnswerStubbing() {
         doAnswer(null);
@@ -94,6 +96,7 @@
         detectsAndCleansUp(new OnDoAnswer(), UnfinishedStubbingException.class);
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldDetectUnfinishedVerification() {
         verify(mock);
@@ -149,6 +152,7 @@
         } catch (RuntimeException e) {}
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldCorrectStateAfterDetectingUnfinishedVerification() {
         mock.simpleMethod();
@@ -167,36 +171,42 @@
     }
 
     private static class OnVerify implements DetectsInvalidState {
+        @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
         public void detect(IMethods mock) {
             verify(mock);
         }
     }
 
     private static class OnVerifyInOrder implements DetectsInvalidState {
+        @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
         public void detect(IMethods mock) {
             inOrder(mock).verify(mock);
         }
     }
 
     private static class OnVerifyZeroInteractions implements DetectsInvalidState {
+        @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
         public void detect(IMethods mock) {
             verifyZeroInteractions(mock);
         }
     }
 
     private static class OnVerifyNoMoreInteractions implements DetectsInvalidState {
+        @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
         public void detect(IMethods mock) {
             verifyNoMoreInteractions(mock);
         }
     }
 
     private static class OnDoAnswer implements DetectsInvalidState {
+        @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
         public void detect(IMethods mock) {
             doAnswer(null);
         }
     }
 
     private static class OnStub implements DetectsInvalidState {
+        @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
         public void detect(IMethods mock) {
             when(mock);
         }
@@ -209,12 +219,14 @@
     }
 
     private static class OnMockCreation implements DetectsInvalidState {
+        @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
         public void detect(IMethods mock) {
             mock(IMethods.class);
         }
     }
 
     private static class OnSpyCreation implements DetectsInvalidState {
+        @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
         public void detect(IMethods mock) {
             spy(new Object());
         }
diff --git a/src/test/java/org/mockito/internal/framework/DefaultMockitoFrameworkTest.java b/src/test/java/org/mockito/internal/framework/DefaultMockitoFrameworkTest.java
index 61646d7..0937b69 100644
--- a/src/test/java/org/mockito/internal/framework/DefaultMockitoFrameworkTest.java
+++ b/src/test/java/org/mockito/internal/framework/DefaultMockitoFrameworkTest.java
@@ -74,6 +74,7 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void removes_creation_listener() {
         //given creation listener is added
diff --git a/src/test/java/org/mockito/internal/invocation/InvocationsFinderTest.java b/src/test/java/org/mockito/internal/invocation/InvocationsFinderTest.java
index b07ece4..7172998 100644
--- a/src/test/java/org/mockito/internal/invocation/InvocationsFinderTest.java
+++ b/src/test/java/org/mockito/internal/invocation/InvocationsFinderTest.java
@@ -185,4 +185,15 @@
         previous = InvocationsFinder.findPreviousVerifiedInOrder(invocations, context);
         assertSame(simpleMethodInvocationTwo, previous);
     }
+
+    @Test
+    public void shouldFindAllStackTraces() {
+        List<Location> all = InvocationsFinder.getAllLocations(invocations);
+        Assertions.assertThat(all).contains(simpleMethodInvocation.getLocation(), simpleMethodInvocationTwo.getLocation(), differentMethodInvocation.getLocation());
+    }
+
+    @Test
+    public void shouldNotFindLocationsForEmptyInvocationsList() {
+        Assertions.assertThat(InvocationsFinder.getAllLocations(Collections.<Invocation>emptyList())).isEmpty();
+    }
 }
diff --git a/src/test/java/org/mockito/internal/invocation/MatcherApplicationStrategyTest.java b/src/test/java/org/mockito/internal/invocation/MatcherApplicationStrategyTest.java
index ce389b0..46a75eb 100644
--- a/src/test/java/org/mockito/internal/invocation/MatcherApplicationStrategyTest.java
+++ b/src/test/java/org/mockito/internal/invocation/MatcherApplicationStrategyTest.java
@@ -14,13 +14,17 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
+import org.mockito.internal.hamcrest.HamcrestArgumentMatcher;
 import org.mockito.internal.matchers.Any;
 import org.mockito.internal.matchers.Equals;
 import org.mockito.internal.matchers.InstanceOf;
+import org.mockito.internal.matchers.VarargMatcher;
 import org.mockito.invocation.Invocation;
 import org.mockitousage.IMethods;
 import org.mockitoutil.TestBase;
@@ -186,6 +190,27 @@
         recordAction.assertContainsExactly(ANY, ANY);
     }
 
+    @Test
+    public void shouldMatchAnyVarargEvenIfMatcherIsWrappedInHamcrestMatcher() {
+        // given
+        invocation = varargs("1", "2");
+        HamcrestArgumentMatcher argumentMatcher = new HamcrestArgumentMatcher(new IntMatcher());
+        matchers = asList(argumentMatcher);
+
+        // when
+        getMatcherApplicationStrategyFor(invocation, matchers).forEachMatcherAndArgument(recordAction);
+
+        // then
+        recordAction.assertContainsExactly(argumentMatcher, argumentMatcher);
+    }
+
+    class IntMatcher extends BaseMatcher<Integer> implements VarargMatcher {
+        public boolean matches(Object o) {
+            return true;
+        }
+        public void describeTo(Description description) {}
+    }
+
     private Invocation mixedVarargs(Object a, String... s) {
         mock.mixedVarargs(a, s);
         return getLastInvocation();
diff --git a/src/test/java/org/mockito/internal/junit/JUnitRuleTest.java b/src/test/java/org/mockito/internal/junit/JUnitRuleTest.java
index c4a8b53..7d5968d 100644
--- a/src/test/java/org/mockito/internal/junit/JUnitRuleTest.java
+++ b/src/test/java/org/mockito/internal/junit/JUnitRuleTest.java
@@ -32,12 +32,14 @@
         throw new RuntimeException("foo");
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void detects_invalid_mockito_usage_on_success() throws Throwable {
         rule.expectFailure(UnfinishedStubbingException.class);
         when(mock.simpleMethod());
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void does_not_check_invalid_mockito_usage_on_failure() throws Throwable {
         //This intended behavior is questionable
diff --git a/src/test/java/org/mockito/internal/junit/UnusedStubbingsTest.java b/src/test/java/org/mockito/internal/junit/UnusedStubbingsTest.java
index 8d11dc2..af1d3a1 100644
--- a/src/test/java/org/mockito/internal/junit/UnusedStubbingsTest.java
+++ b/src/test/java/org/mockito/internal/junit/UnusedStubbingsTest.java
@@ -4,9 +4,6 @@
  */
 package org.mockito.internal.junit;
 
-import java.util.Arrays;
-import java.util.Collections;
-
 import org.junit.Test;
 import org.mockito.internal.invocation.InvocationBuilder;
 import org.mockito.internal.stubbing.StubbedInvocationMatcher;
@@ -14,6 +11,9 @@
 import org.mockito.stubbing.Stubbing;
 import org.mockitoutil.TestBase;
 
+import java.util.Arrays;
+import java.util.Collections;
+
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.internal.stubbing.answers.DoesNothing.doesNothing;
@@ -38,8 +38,8 @@
     public void unused_stubbings() throws Exception {
         //given
         UnusedStubbings stubbings = new UnusedStubbings(Arrays.asList(
-            new StubbedInvocationMatcher(new InvocationBuilder().toInvocationMatcher(), doesNothing()),
-            new StubbedInvocationMatcher(new InvocationBuilder().toInvocationMatcher(), doesNothing())
+            new StubbedInvocationMatcher(doesNothing(), new InvocationBuilder().toInvocationMatcher(), null),
+            new StubbedInvocationMatcher(doesNothing(), new InvocationBuilder().toInvocationMatcher(), null)
         ));
 
 
diff --git a/src/test/java/org/mockito/internal/listeners/StubbingLookupNotifierTest.java b/src/test/java/org/mockito/internal/listeners/StubbingLookupNotifierTest.java
new file mode 100644
index 0000000..ac963c4
--- /dev/null
+++ b/src/test/java/org/mockito/internal/listeners/StubbingLookupNotifierTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockito.internal.listeners;
+
+import org.assertj.core.util.Lists;
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+import org.mockito.internal.creation.settings.CreationSettings;
+import org.mockito.invocation.Invocation;
+import org.mockito.stubbing.Stubbing;
+import org.mockitoutil.TestBase;
+
+import java.util.Collection;
+import java.util.List;
+
+import static org.assertj.core.util.Lists.emptyList;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.internal.listeners.StubbingLookupNotifier.notifyStubbedAnswerLookup;
+
+public class StubbingLookupNotifierTest extends TestBase {
+
+    Invocation invocation = mock(Invocation.class);
+    Stubbing stubbingFound = mock(Stubbing.class);
+    Collection<Stubbing> allStubbings = mock(Collection.class);
+    CreationSettings creationSettings = mock(CreationSettings.class);
+
+    @Test
+    public void does_not_do_anything_when_list_is_empty() {
+        // given
+        doReturn(emptyList()).when(creationSettings).getStubbingLookupListeners();
+
+        // when
+        notifyStubbedAnswerLookup(invocation, stubbingFound, allStubbings, creationSettings);
+
+        // then expect nothing to happen
+    }
+
+    @Test
+    public void call_on_stubbing_lookup_method_of_listeners_with_correct_event() {
+        // given
+        StubbingLookupListener listener1 = mock(StubbingLookupListener.class);
+        StubbingLookupListener listener2 = mock(StubbingLookupListener.class);
+        List<StubbingLookupListener> listeners = Lists.newArrayList(listener1, listener2);
+        doReturn(listeners).when(creationSettings).getStubbingLookupListeners();
+
+        // when
+        notifyStubbedAnswerLookup(invocation, stubbingFound, allStubbings, creationSettings);
+
+        // then
+        verify(listener1).onStubbingLookup(argThat(new EventArgumentMatcher()));
+        verify(listener2).onStubbingLookup(argThat(new EventArgumentMatcher()));
+    }
+
+    class EventArgumentMatcher implements ArgumentMatcher<StubbingLookupNotifier.Event> {
+
+        @Override
+        public boolean matches(StubbingLookupNotifier.Event argument) {
+            return invocation == argument.getInvocation() &&
+                stubbingFound == argument.getStubbingFound() &&
+                allStubbings == argument.getAllStubbings() &&
+                creationSettings == argument.getMockSettings();
+        }
+    }
+}
diff --git a/src/test/java/org/mockito/internal/progress/ThreadSafeMockingProgressTest.java b/src/test/java/org/mockito/internal/progress/ThreadSafeMockingProgressTest.java
index 5535eec..673ca10 100644
--- a/src/test/java/org/mockito/internal/progress/ThreadSafeMockingProgressTest.java
+++ b/src/test/java/org/mockito/internal/progress/ThreadSafeMockingProgressTest.java
@@ -34,6 +34,7 @@
         assertNotNull(p.pullVerificationMode());
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldKnowWhenVerificationHasStarted() throws Exception {
         //given
diff --git a/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java b/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java
index de5eb13..52e481d 100644
--- a/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java
+++ b/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplStubbingTest.java
@@ -46,7 +46,7 @@
     public void should_finish_stubbing_when_wrong_throwable_is_set() throws Exception {
         state.stubbingStarted();
         try {
-            invocationContainerImpl.addAnswer(new ThrowsException(new Exception()));
+            invocationContainerImpl.addAnswer(new ThrowsException(new Exception()), null);
             fail();
         } catch (MockitoException e) {
             state.validateState();
@@ -56,18 +56,18 @@
     @Test
     public void should_finish_stubbing_on_adding_return_value() throws Exception {
         state.stubbingStarted();
-        invocationContainerImpl.addAnswer(new Returns("test"));
+        invocationContainerImpl.addAnswer(new Returns("test"), null);
         state.validateState();
     }
 
     @Test
     public void should_get_results_for_methods() throws Throwable {
         invocationContainerImpl.setInvocationForPotentialStubbing(new InvocationMatcher(simpleMethod));
-        invocationContainerImpl.addAnswer(new Returns("simpleMethod"));
+        invocationContainerImpl.addAnswer(new Returns("simpleMethod"), null);
 
         Invocation differentMethod = new InvocationBuilder().differentMethod().toInvocation();
         invocationContainerImpl.setInvocationForPotentialStubbing(new InvocationMatcher(differentMethod));
-        invocationContainerImpl.addAnswer(new ThrowsException(new MyException()));
+        invocationContainerImpl.addAnswer(new ThrowsException(new MyException()), null);
 
         assertEquals("simpleMethod", invocationContainerImpl.answerTo(simpleMethod));
 
@@ -80,11 +80,11 @@
     @Test
     public void should_get_results_for_methods_stub_only() throws Throwable {
         invocationContainerImplStubOnly.setInvocationForPotentialStubbing(new InvocationMatcher(simpleMethod));
-        invocationContainerImplStubOnly.addAnswer(new Returns("simpleMethod"));
+        invocationContainerImplStubOnly.addAnswer(new Returns("simpleMethod"), null);
 
         Invocation differentMethod = new InvocationBuilder().differentMethod().toInvocation();
         invocationContainerImplStubOnly.setInvocationForPotentialStubbing(new InvocationMatcher(differentMethod));
-        invocationContainerImplStubOnly.addAnswer(new ThrowsException(new MyException()));
+        invocationContainerImplStubOnly.addAnswer(new ThrowsException(new MyException()), null);
 
         assertEquals("simpleMethod", invocationContainerImplStubOnly.answerTo(simpleMethod));
 
@@ -97,7 +97,7 @@
     @Test
     public void should_validate_throwable() throws Throwable {
         try {
-            invocationContainerImpl.addAnswer(new ThrowsException(null));
+            invocationContainerImpl.addAnswer(new ThrowsException(null), null);
             fail();
         } catch (MockitoException e) {}
     }
diff --git a/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplTest.java b/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplTest.java
index 176372f..c63d6e9 100644
--- a/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplTest.java
+++ b/src/test/java/org/mockito/internal/stubbing/InvocationContainerImplTest.java
@@ -4,12 +4,6 @@
  */
 package org.mockito.internal.stubbing;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import java.util.LinkedList;
-import java.util.concurrent.CountDownLatch;
 import org.junit.Test;
 import org.mockito.internal.creation.MockSettingsImpl;
 import org.mockito.internal.invocation.InvocationBuilder;
@@ -19,6 +13,13 @@
 import org.mockito.invocation.Invocation;
 import org.mockito.mock.MockCreationSettings;
 
+import java.util.LinkedList;
+import java.util.concurrent.CountDownLatch;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 /**
  * Author: Szczepan Faber
  */
@@ -54,7 +55,7 @@
                         throw new RuntimeException(e);
                     }
                     c.setInvocationForPotentialStubbing(new InvocationMatcher(invocation));
-                    c.addAnswer(new Returns("foo"));
+                    c.addAnswer(new Returns("foo"), null);
                     c.findAnswerFor(invocation);
                 }
             };
@@ -98,7 +99,7 @@
         container.setInvocationForPotentialStubbing(new InvocationBuilder().toInvocationMatcher());
         assertTrue(container.hasInvocationForPotentialStubbing());
 
-        container.addAnswer(new ReturnsEmptyValues());
+        container.addAnswer(new ReturnsEmptyValues(), null);
         assertFalse(container.hasInvocationForPotentialStubbing());
     }
 
@@ -107,7 +108,7 @@
         containerStubOnly.setInvocationForPotentialStubbing(new InvocationBuilder().toInvocationMatcher());
         assertTrue(containerStubOnly.hasInvocationForPotentialStubbing());
 
-        containerStubOnly.addAnswer(new ReturnsEmptyValues());
+        containerStubOnly.addAnswer(new ReturnsEmptyValues(), null);
         assertFalse(containerStubOnly.hasInvocationForPotentialStubbing());
     }
 }
diff --git a/src/test/java/org/mockito/internal/stubbing/answers/ThrowsExceptionTest.java b/src/test/java/org/mockito/internal/stubbing/answers/ThrowsExceptionTest.java
index 8b553aa..2e71102 100644
--- a/src/test/java/org/mockito/internal/stubbing/answers/ThrowsExceptionTest.java
+++ b/src/test/java/org/mockito/internal/stubbing/answers/ThrowsExceptionTest.java
@@ -10,7 +10,9 @@
 import org.junit.Test;
 import org.mockito.exceptions.base.MockitoException;
 import org.mockito.internal.invocation.InvocationBuilder;
+import org.mockito.invocation.Invocation;
 
+import static junit.framework.TestCase.fail;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 
@@ -19,7 +21,7 @@
     @Test
     public void should_raise_wanted_throwable() throws Throwable {
         try {
-            new ThrowsException(new IllegalStateException("my dear throwable")).answer(new InvocationBuilder().method("canThrowException").toInvocation());
+            new ThrowsException(new IllegalStateException("my dear throwable")).answer(createMethodInvocation());
             Assertions.fail("should have raised wanted exception");
         } catch (Throwable throwable) {
             assertThat(throwable).isInstanceOf(IllegalStateException.class).hasMessage("my dear throwable");
@@ -29,7 +31,7 @@
     @Test
     public void should_throw_mock_exception_without_stacktrace() throws Exception {
         try {
-            new ThrowsException(mock(Exception.class)).answer(new InvocationBuilder().method("canThrowException").toInvocation());
+            new ThrowsException(mock(Exception.class)).answer(createMethodInvocation());
             Assertions.fail("should have raised wanted exception");
         } catch (Throwable throwable) {
             assertThat(throwable.getStackTrace()).describedAs("no stack trace, it's mock").isNull();
@@ -46,7 +48,7 @@
         try {
 
             // when
-            new ThrowsException(throwableToRaise).answer(new InvocationBuilder().method("canThrowException").toInvocation());
+            new ThrowsException(throwableToRaise).answer(createMethodInvocation());
             Assertions.fail("should have raised wanted exception");
         } catch (Throwable throwable) {
             // then
@@ -59,24 +61,42 @@
     @Test
     public void should_invalidate_null_throwable() throws Throwable {
         try {
-            new ThrowsException(null).validateFor(new InvocationBuilder().toInvocation());
+            Invocation invocation = createMethodInvocation();
+            new ThrowsException(null).validateFor(invocation);
             Assertions.fail("should have raised a MockitoException");
         } catch (MockitoException expected) {}
     }
 
     @Test
+    public void should_throw_illegal_state_exception_if_null_answer() throws Throwable {
+        Invocation invocation = createMethodInvocation();
+        try {
+            new ThrowsException(null).answer(invocation);
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    @Test
     public void should_pass_proper_checked_exception() throws Throwable {
-        new ThrowsException(new CharacterCodingException()).validateFor(new InvocationBuilder().method("canThrowException").toInvocation());
+        new ThrowsException(new CharacterCodingException()).validateFor(createMethodInvocation());
     }
 
     @Test(expected = MockitoException.class)
     public void should_fail_invalid_checked_exception() throws Throwable {
-        new ThrowsException(new IOException()).validateFor(new InvocationBuilder().method("canThrowException").toInvocation());
+        new ThrowsException(new IOException()).validateFor(createMethodInvocation());
     }
 
     @Test
     public void should_pass_RuntimeExceptions() throws Throwable {
-        new ThrowsException(new Error()).validateFor(new InvocationBuilder().method("canThrowException").toInvocation());
-        new ThrowsException(new RuntimeException()).validateFor(new InvocationBuilder().method("canThrowException").toInvocation());
+        new ThrowsException(new Error()).validateFor(createMethodInvocation());
+        new ThrowsException(new RuntimeException()).validateFor(createMethodInvocation());
+    }
+
+    /** Creates Invocation of a "canThrowException" method call. */
+    private static Invocation createMethodInvocation() {
+        return new InvocationBuilder()
+            .method("canThrowException")
+            .toInvocation();
     }
 }
diff --git a/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsEmptyValuesTest.java b/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsEmptyValuesTest.java
index 945cf08..68fbaf5 100644
--- a/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsEmptyValuesTest.java
+++ b/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsEmptyValuesTest.java
@@ -74,6 +74,7 @@
         assertTrue(result != (Object) 0);
     }
 
+    @SuppressWarnings("SelfComparison")
     @Test
     public void should_return_zero_if_mock_is_compared_to_itself() {
         //given
diff --git a/src/test/java/org/mockito/internal/util/PrimitivesTest.java b/src/test/java/org/mockito/internal/util/PrimitivesTest.java
index 2896bd4..34dd362 100644
--- a/src/test/java/org/mockito/internal/util/PrimitivesTest.java
+++ b/src/test/java/org/mockito/internal/util/PrimitivesTest.java
@@ -69,21 +69,21 @@
 
     @Test
     public void should_check_that_value_type_is_assignable_to_wrapper_reference() {
-        assertThat(Primitives.isAssignableFromWrapper(int.class, Integer.class));
-        assertThat(Primitives.isAssignableFromWrapper(Integer.class, Integer.class));
-        assertThat(Primitives.isAssignableFromWrapper(long.class, Long.class));
-        assertThat(Primitives.isAssignableFromWrapper(Long.class, Long.class));
-        assertThat(Primitives.isAssignableFromWrapper(double.class, Double.class));
-        assertThat(Primitives.isAssignableFromWrapper(Double.class, Double.class));
-        assertThat(Primitives.isAssignableFromWrapper(float.class, Float.class));
-        assertThat(Primitives.isAssignableFromWrapper(Float.class, Float.class));
-        assertThat(Primitives.isAssignableFromWrapper(char.class, Character.class));
-        assertThat(Primitives.isAssignableFromWrapper(Character.class, Character.class));
-        assertThat(Primitives.isAssignableFromWrapper(short.class, Short.class));
-        assertThat(Primitives.isAssignableFromWrapper(Short.class, Short.class));
-        assertThat(Primitives.isAssignableFromWrapper(byte.class, Byte.class));
-        assertThat(Primitives.isAssignableFromWrapper(Byte.class, Byte.class));
-        assertThat(Primitives.isAssignableFromWrapper(boolean.class, Boolean.class));
-        assertThat(Primitives.isAssignableFromWrapper(Boolean.class, Boolean.class));
+        assertThat(Primitives.isAssignableFromWrapper(int.class, Integer.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(Integer.class, Integer.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(long.class, Long.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(Long.class, Long.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(double.class, Double.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(Double.class, Double.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(float.class, Float.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(Float.class, Float.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(char.class, Character.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(Character.class, Character.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(short.class, Short.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(Short.class, Short.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(byte.class, Byte.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(Byte.class, Byte.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(boolean.class, Boolean.class)).isTrue();
+        assertThat(Primitives.isAssignableFromWrapper(Boolean.class, Boolean.class)).isTrue();
     }
 }
diff --git a/src/test/java/org/mockito/internal/verification/checkers/NumberOfInvocationsCheckerTest.java b/src/test/java/org/mockito/internal/verification/checkers/NumberOfInvocationsCheckerTest.java
index af9d3cb..61b2f2e 100644
--- a/src/test/java/org/mockito/internal/verification/checkers/NumberOfInvocationsCheckerTest.java
+++ b/src/test/java/org/mockito/internal/verification/checkers/NumberOfInvocationsCheckerTest.java
@@ -5,10 +5,6 @@
 
 package org.mockito.internal.verification.checkers;
 
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static org.assertj.core.api.Assertions.assertThat;
-
 import java.util.List;
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
@@ -28,6 +24,10 @@
 import org.mockito.junit.MockitoJUnitRunner;
 import org.mockitousage.IMethods;
 
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static org.assertj.core.api.Assertions.assertThat;
+
 @RunWith(MockitoJUnitRunner.class)
 public class NumberOfInvocationsCheckerTest {
 
@@ -58,7 +58,7 @@
     }
 
     @Test
-    public void shouldReportWithLastInvocationStackTrace() throws Exception {
+    public void shouldReportAllInvocationsStackTrace() throws Exception {
         wanted = buildSimpleMethod().toInvocationMatcher();
         invocations = asList(buildSimpleMethod().toInvocation(), buildSimpleMethod().toInvocation());
 
@@ -66,7 +66,7 @@
         exception.expectMessage("mock.simpleMethod()");
         exception.expectMessage("Wanted 100 times");
         exception.expectMessage("But was 2 times");
-        exception.expectMessage(containsTimes("-> at", 2));
+        exception.expectMessage(containsTimes("-> at", 3));
 
         NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 100);
     }
@@ -86,7 +86,7 @@
     }
 
     @Test
-    public void shouldReportWithFirstUndesiredInvocationStackTrace() throws Exception {
+    public void shouldReportWithAllInvocationsStackTrace() throws Exception {
         Invocation first = buildSimpleMethod().toInvocation();
         Invocation second = buildSimpleMethod().toInvocation();
         Invocation third = buildSimpleMethod().toInvocation();
@@ -95,6 +95,8 @@
         wanted = buildSimpleMethod().toInvocationMatcher();
 
         exception.expect(TooManyActualInvocations.class);
+        exception.expectMessage("" + first.getLocation());
+        exception.expectMessage("" + second.getLocation());
         exception.expectMessage("" + third.getLocation());
         NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 2);
     }
diff --git a/src/test/java/org/mockito/internal/verification/checkers/NumberOfInvocationsInOrderCheckerTest.java b/src/test/java/org/mockito/internal/verification/checkers/NumberOfInvocationsInOrderCheckerTest.java
index 2e72033..bc031ac 100644
--- a/src/test/java/org/mockito/internal/verification/checkers/NumberOfInvocationsInOrderCheckerTest.java
+++ b/src/test/java/org/mockito/internal/verification/checkers/NumberOfInvocationsInOrderCheckerTest.java
@@ -5,11 +5,6 @@
 
 package org.mockito.internal.verification.checkers;
 
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptyList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
 import java.util.List;
 
 import org.hamcrest.BaseMatcher;
@@ -27,6 +22,11 @@
 import org.mockito.invocation.Invocation;
 import org.mockitousage.IMethods;
 
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
 public class NumberOfInvocationsInOrderCheckerTest {
 
     private InvocationMatcher wanted;
@@ -102,7 +102,7 @@
     }
 
     @Test
-    public void shouldReportWithLastInvocationStackTrace() throws Exception {
+    public void shouldReportWithAllInvocationsStackTrace() throws Exception {
         wanted = buildSimpleMethod().toInvocationMatcher();
         invocations = asList(buildSimpleMethod().toInvocation(), buildSimpleMethod().toInvocation());
 
@@ -110,7 +110,7 @@
         exception.expectMessage("mock.simpleMethod()");
         exception.expectMessage("Wanted 100 times");
         exception.expectMessage("But was 2 times");
-        exception.expectMessage(containsTimes("-> at", 2));
+        exception.expectMessage(containsTimes("-> at", 3));
 
         NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 100, context);
 
@@ -168,7 +168,7 @@
         exception.expect(VerificationInOrderFailure.class);
         exception.expectMessage("mock.simpleMethod()");
         exception.expectMessage("Wanted 0 times");
-        exception.expectMessage("But was 1 time. Undesired invocation");
+        exception.expectMessage("But was 1 time:");
         exception.expectMessage("" + first.getLocation());
 
         NumberOfInvocationsChecker.checkNumberOfInvocations(invocations, wanted, 0, context);
diff --git a/src/test/java/org/mockitousage/basicapi/MocksCreationTest.java b/src/test/java/org/mockitousage/basicapi/MocksCreationTest.java
index 5d2af03..98ab7d2 100644
--- a/src/test/java/org/mockitousage/basicapi/MocksCreationTest.java
+++ b/src/test/java/org/mockitousage/basicapi/MocksCreationTest.java
@@ -90,6 +90,7 @@
         } catch (MockitoException e) {}
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldAllowCreatingSpiesWithCorrectType() {
         List list = new LinkedList();
diff --git a/src/test/java/org/mockitousage/basicapi/MocksSerializationForAnnotationTest.java b/src/test/java/org/mockitousage/basicapi/MocksSerializationForAnnotationTest.java
index 5231a1b..31cdd04 100644
--- a/src/test/java/org/mockitousage/basicapi/MocksSerializationForAnnotationTest.java
+++ b/src/test/java/org/mockitousage/basicapi/MocksSerializationForAnnotationTest.java
@@ -19,7 +19,6 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Observable;
@@ -254,19 +253,19 @@
     @Test
     public void should_serialize_with_real_object_spy() throws Exception {
         // given
-        List<Object> list = new ArrayList<Object>();
-        List<Object> spy = mock(ArrayList.class, withSettings()
+        SerializableSample list = new SerializableSample();
+        SerializableSample spy = mock(SerializableSample.class, withSettings()
                         .spiedInstance(list)
                         .defaultAnswer(CALLS_REAL_METHODS)
                         .serializable());
-        when(spy.size()).thenReturn(100);
+        when(spy.foo()).thenReturn("foo");
 
         // when
         ByteArrayOutputStream serialized = serializeMock(spy);
 
         // then
-        List<?> readObject = deserializeMock(serialized, List.class);
-        assertEquals(100, readObject.size());
+        SerializableSample readObject = deserializeMock(serialized, SerializableSample.class);
+        assertEquals("foo", readObject.foo());
     }
 
     @Test
@@ -313,14 +312,10 @@
                 .isInstanceOf(IMethods.class);
     }
 
-
-
     static class NotSerializableAndNoDefaultConstructor {
         NotSerializableAndNoDefaultConstructor(Observable o) { super(); }
     }
 
-
-
     static class SerializableAndNoDefaultConstructor implements Serializable {
         SerializableAndNoDefaultConstructor(Observable o) { super(); }
     }
@@ -337,4 +332,11 @@
 
         serializeAndBack(testClass.serializableAndNoDefaultConstructor);
     }
+
+    public static class SerializableSample implements Serializable {
+
+        public String foo() {
+            return null;
+        }
+    }
 }
diff --git a/src/test/java/org/mockitousage/basicapi/MocksSerializationTest.java b/src/test/java/org/mockitousage/basicapi/MocksSerializationTest.java
index 6445aa0..02bcc3d 100644
--- a/src/test/java/org/mockitousage/basicapi/MocksSerializationTest.java
+++ b/src/test/java/org/mockitousage/basicapi/MocksSerializationTest.java
@@ -5,6 +5,7 @@
 
 package org.mockitousage.basicapi;
 
+import net.bytebuddy.ClassFileVersion;
 import org.assertj.core.api.Assertions;
 import org.junit.Test;
 import org.mockito.InOrder;
@@ -20,13 +21,12 @@
 import java.io.ByteArrayOutputStream;
 import java.io.ObjectStreamException;
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Observable;
 
 import static org.junit.Assert.*;
-import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.Mockito.*;
 import static org.mockitoutil.SimpleSerializationUtil.*;
 
@@ -275,19 +275,19 @@
     @Test
     public void should_serialize_with_real_object_spy() throws Exception {
         // given
-        List<Object> list = new ArrayList<Object>();
-        List<Object> spy = mock(ArrayList.class, withSettings()
-                .spiedInstance(list)
+        SerializableClass sample = new SerializableClass();
+        SerializableClass spy = mock(SerializableClass.class, withSettings()
+                .spiedInstance(sample)
                 .defaultAnswer(CALLS_REAL_METHODS)
                 .serializable());
-        when(spy.size()).thenReturn(100);
+        when(spy.foo()).thenReturn("foo");
 
         // when
         ByteArrayOutputStream serialized = serializeMock(spy);
 
         // then
-        List<?> readObject = deserializeMock(serialized, List.class);
-        assertEquals(100, readObject.size());
+        SerializableClass readObject = deserializeMock(serialized, SerializableClass.class);
+        assertEquals("foo", readObject.foo());
     }
 
     @Test
@@ -346,8 +346,6 @@
                 .isInstanceOf(IMethods.class);
     }
 
-
-
     static class SerializableAndNoDefaultConstructor implements Serializable {
         SerializableAndNoDefaultConstructor(Observable o) { super(); }
     }
@@ -385,7 +383,7 @@
 
     @Test
     public void BUG_ISSUE_399_try_some_mocks_with_current_answers() throws Exception {
-        assumeFalse(System.getProperty("java.version").startsWith("1.6")); // Bug in last public HotSpot 1.6
+        assumeTrue(ClassFileVersion.ofThisVm().isAtLeast(ClassFileVersion.JAVA_V7));
 
         IMethods iMethods = mock(IMethods.class, withSettings().serializable().defaultAnswer(RETURNS_DEEP_STUBS));
 
@@ -393,4 +391,11 @@
 
         serializeAndBack(iMethods);
     }
+
+    public static class SerializableClass implements Serializable {
+
+        public String foo() {
+            return null;
+        }
+    }
 }
diff --git a/src/test/java/org/mockitousage/basicapi/ResetTest.java b/src/test/java/org/mockitousage/basicapi/ResetTest.java
index 150945f..ef199a5 100644
--- a/src/test/java/org/mockitousage/basicapi/ResetTest.java
+++ b/src/test/java/org/mockitousage/basicapi/ResetTest.java
@@ -26,7 +26,6 @@
 
     @Test
     public void shouldResetOngoingStubbingSoThatMoreMeaningfulExceptionsAreRaised() {
-        mock(IMethods.class);
         mock.booleanReturningMethod();
         reset(mock);
         try {
@@ -95,6 +94,7 @@
         verifyNoMoreInteractions(mock, mockTwo);
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test
     public void shouldValidateStateWhenResetting() {
         //invalid verify:
diff --git a/src/test/java/org/mockitousage/bugs/ActualInvocationHasNullArgumentNPEBugTest.java b/src/test/java/org/mockitousage/bugs/ActualInvocationHasNullArgumentNPEBugTest.java
index b4f38bf..632c8c9 100644
--- a/src/test/java/org/mockitousage/bugs/ActualInvocationHasNullArgumentNPEBugTest.java
+++ b/src/test/java/org/mockitousage/bugs/ActualInvocationHasNullArgumentNPEBugTest.java
@@ -29,9 +29,10 @@
         //then
         try {
             verify(mockFun).doFun("hello");
-            fail();
         } catch(AssertionError r) {
             //it's ok, we just want to reproduce the bug
+            return;
         }
+        fail();
     }
 }
diff --git a/src/test/java/org/mockitousage/bugs/FillInStackTraceScenariosTest.java b/src/test/java/org/mockitousage/bugs/FillInStackTraceScenariosTest.java
new file mode 100644
index 0000000..5e3193e
--- /dev/null
+++ b/src/test/java/org/mockitousage/bugs/FillInStackTraceScenariosTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitousage.bugs;
+
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockitousage.IMethods;
+import org.mockitoutil.TestBase;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.when;
+
+/**
+ * These tests check that ThrowsException#answer throws an instance returned
+ * by Throwable#fillInStackTrace of the provided throwable.
+ *
+ * <p>A well-behaved Throwable implementation must always return a reference to this
+ * from #fillInStackTrace according to the method contract.
+ * However, Mockito throws the exception returned from #fillInStackTrace for backwards compatibility
+ * (or the provided exception if the method returns null).
+ *
+ * @see Throwable#fillInStackTrace()
+ * @see <a href="https://github.com/mockito/mockito/issues/866">#866</a>
+ */
+public class FillInStackTraceScenariosTest extends TestBase {
+
+    @Mock IMethods mock;
+
+    private class SomeException extends RuntimeException {}
+
+    class NullStackTraceException extends RuntimeException {
+        public Exception fillInStackTrace() {
+            return null;
+        }
+    }
+
+    class NewStackTraceException extends RuntimeException {
+        public Exception fillInStackTrace() {
+            return new SomeException();
+        }
+    }
+
+    //issue 866
+    @Test
+    public void avoids_NPE() {
+        when(mock.simpleMethod()).thenThrow(new NullStackTraceException());
+        try {
+            mock.simpleMethod();
+            fail();
+        } catch(NullStackTraceException e) {}
+    }
+
+    @Test
+    public void uses_return_value_from_fillInStackTrace() {
+        when(mock.simpleMethod()).thenThrow(new NewStackTraceException());
+        try {
+            mock.simpleMethod();
+            fail();
+        } catch(SomeException e) {}
+    }
+}
diff --git a/src/test/java/org/mockitousage/bugs/NPEWhenCustomExceptionStackTraceReturnNullTest.java b/src/test/java/org/mockitousage/bugs/NPEWhenCustomExceptionStackTraceReturnNullTest.java
deleted file mode 100644
index 92a1305..0000000
--- a/src/test/java/org/mockitousage/bugs/NPEWhenCustomExceptionStackTraceReturnNullTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2017 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockitousage.bugs;
-
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockitousage.IMethods;
-import org.mockitoutil.TestBase;
-
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.when;
-
-public class NPEWhenCustomExceptionStackTraceReturnNullTest extends TestBase {
-
-    @Mock
-    IMethods mock;
-
-    class NullStackTraceException extends RuntimeException {
-        @Override
-        public Exception fillInStackTrace() {
-            return null;
-        }
-    }
-
-    //issue 866
-    @Test
-    public void shouldNotThrowNPE() {
-        when(mock.simpleMethod()).thenThrow(new NullStackTraceException());
-        try {
-            mock.simpleMethod();
-            fail();
-        } catch(NullStackTraceException e) {}
-    }
-}
diff --git a/src/test/java/org/mockitousage/bugs/varargs/VarargsNotPlayingWithAnyObjectTest.java b/src/test/java/org/mockitousage/bugs/varargs/VarargsNotPlayingWithAnyObjectTest.java
index 9a96741..2b0cbff 100644
--- a/src/test/java/org/mockitousage/bugs/varargs/VarargsNotPlayingWithAnyObjectTest.java
+++ b/src/test/java/org/mockitousage/bugs/varargs/VarargsNotPlayingWithAnyObjectTest.java
@@ -10,8 +10,13 @@
 import org.mockitoutil.TestBase;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.anyVararg;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 //see issue 62
 public class VarargsNotPlayingWithAnyObjectTest extends TestBase {
@@ -35,16 +40,10 @@
         verify(mock, never()).run(anyString(), eq("f"));
     }
 
-    //we cannot use anyObject() for entire varargs because it makes the verification pick up extra invocations
-    //see other tests in this package
     @Test
-    public void shouldNotAllowUsingAnyObjectForVarArgs() {
+    public void shouldAllowUsingAnyObjectForVarArgs() {
         mock.run("a", "b");
-
-        try {
-            verify(mock).run((String[]) anyObject());
-            fail();
-        } catch (AssertionError e) {}
+        verify(mock).run((String[]) anyObject());
     }
 
     @Test
diff --git a/src/test/java/org/mockitousage/constructor/CreatingMocksWithConstructorTest.java b/src/test/java/org/mockitousage/constructor/CreatingMocksWithConstructorTest.java
index 8b0332d..fe626b0 100644
--- a/src/test/java/org/mockitousage/constructor/CreatingMocksWithConstructorTest.java
+++ b/src/test/java/org/mockitousage/constructor/CreatingMocksWithConstructorTest.java
@@ -248,6 +248,7 @@
         }
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void mocking_interfaces_with_constructor() {
         //at the moment this is allowed however we can be more strict if needed
diff --git a/src/test/java/org/mockitousage/internal/junit/UnusedStubbingsFinderTest.java b/src/test/java/org/mockitousage/internal/junit/UnusedStubbingsFinderTest.java
index b03d5d7..0eb3d7d 100644
--- a/src/test/java/org/mockitousage/internal/junit/UnusedStubbingsFinderTest.java
+++ b/src/test/java/org/mockitousage/internal/junit/UnusedStubbingsFinderTest.java
@@ -16,6 +16,7 @@
 
 import static java.util.Arrays.asList;
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.when;
 
 /**
@@ -86,10 +87,28 @@
     }
 
     @Test
+    public void unused_and_lenient_stubbings() throws Exception {
+        when(mock1.simpleMethod(1)).thenReturn("1");
+        when(mock1.simpleMethod(2)).thenReturn("2");
+        lenient().when(mock2.simpleMethod(3)).thenReturn("3");
+
+        mock1.simpleMethod(1);
+
+        //when
+        UnusedStubbings stubbings = finder.getUnusedStubbings((List) asList(mock1, mock2));
+
+        //then
+        assertEquals(1, stubbings.size());
+        assertEquals("[mock1.simpleMethod(2); stubbed with: [Returns: 2]]",
+                stubbings.toString());
+    }
+
+    @Test
     public void some_unused_stubbings_by_location() throws Exception {
         when(mock1.simpleMethod(1)).thenReturn("1");
         when(mock2.simpleMethod(2)).thenReturn("2");
         when(mock2.simpleMethod(3)).thenReturn("3");
+        lenient().when(mock2.differentMethod()).thenReturn("4"); //will not be included in results
 
         mock2.simpleMethod(2);
 
diff --git a/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java b/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java
index f4e3e95..b802013 100644
--- a/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java
+++ b/src/test/java/org/mockitousage/junitrule/StrictJUnitRuleTest.java
@@ -157,6 +157,7 @@
         mock2.booleanObjectReturningMethod();
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test public void rule_validates_mockito_usage() throws Throwable {
         //expect
         rule.expectFailure(UnfinishedVerificationException.class);
diff --git a/src/test/java/org/mockitousage/junitrunner/SilentRunnerTest.java b/src/test/java/org/mockitousage/junitrunner/SilentRunnerTest.java
index 284b197..f22d7ac 100644
--- a/src/test/java/org/mockitousage/junitrunner/SilentRunnerTest.java
+++ b/src/test/java/org/mockitousage/junitrunner/SilentRunnerTest.java
@@ -104,6 +104,8 @@
     @RunWith(MockitoJUnitRunner.Silent.class)
     public static class UsesFrameworkIncorrectly {
         @Mock List<?> list;
+
+        @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
         @Test public void unfinished_stubbing_test_method() {
             when(list.get(0)); //unfinished stubbing
         }
diff --git a/src/test/java/org/mockitousage/junitrunner/StubbingWarningsJUnitRunnerTest.java b/src/test/java/org/mockitousage/junitrunner/StubbingWarningsJUnitRunnerTest.java
index bc7fd2b..7d8d537 100644
--- a/src/test/java/org/mockitousage/junitrunner/StubbingWarningsJUnitRunnerTest.java
+++ b/src/test/java/org/mockitousage/junitrunner/StubbingWarningsJUnitRunnerTest.java
@@ -119,6 +119,7 @@
     @RunWith(TestableJUnitRunner.class)
     public static class InvalidMockitoUsage {
         @Mock IMethods mock;
+        @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
         @Test public void test() throws Exception {
             when(mock.simpleMethod()); // <-- unfinished stubbing
         }
diff --git a/src/test/java/org/mockitousage/matchers/MoreMatchersTest.java b/src/test/java/org/mockitousage/matchers/MoreMatchersTest.java
index ad27b48..46773b8 100644
--- a/src/test/java/org/mockitousage/matchers/MoreMatchersTest.java
+++ b/src/test/java/org/mockitousage/matchers/MoreMatchersTest.java
@@ -5,15 +5,16 @@
 
 package org.mockitousage.matchers;
 
+import org.assertj.core.api.ThrowableAssert;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.mockito.exceptions.verification.junit.ArgumentsAreDifferent;
 import org.mockitousage.IMethods;
 import org.mockitoutil.TestBase;
 
 import java.util.*;
-
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
 import static org.mockito.Matchers.*;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -44,16 +45,21 @@
         verify(mock).simpleMethod(isA(List.class));
         verify(mock).simpleMethod(any(List.class));
 
-
         mock.simpleMethod((String) null);
-        try {
-            verify(mock).simpleMethod(isA(String.class));
-            fail();
-        } catch (AssertionError ignored) { }
-        try {
-            verify(mock).simpleMethod(any(String.class));
-            fail();
-        } catch (AssertionError ignored) { }
+
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock).simpleMethod(isA(String.class));
+            }
+        }).isInstanceOf(ArgumentsAreDifferent.class);
+
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock).simpleMethod(any(String.class));
+            }
+        }).isInstanceOf(ArgumentsAreDifferent.class);
     }
 
     @Test
diff --git a/src/test/java/org/mockitousage/misuse/DescriptiveMessagesOnMisuseTest.java b/src/test/java/org/mockitousage/misuse/DescriptiveMessagesOnMisuseTest.java
index 09f0034..41e4a16 100644
--- a/src/test/java/org/mockitousage/misuse/DescriptiveMessagesOnMisuseTest.java
+++ b/src/test/java/org/mockitousage/misuse/DescriptiveMessagesOnMisuseTest.java
@@ -61,6 +61,7 @@
 //        when(mock.differentMethod()).thenReturn("");
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test(expected=NotAMockException.class)
     public void shouldScreamWhenWholeMethodPassedToVerify() {
         verify(mock.booleanReturningMethod());
@@ -71,16 +72,19 @@
         verifyNoMoreInteractions(mock.byteReturningMethod());
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test(expected=NotAMockException.class)
     public void shouldScreamWhenInOrderCreatedWithDodgyMock() {
         inOrder("not a mock");
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test(expected=NullInsteadOfMockException.class)
     public void shouldScreamWhenInOrderCreatedWithNulls() {
         inOrder(mock, null);
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test(expected=NullInsteadOfMockException.class)
     public void shouldScreamNullPassedToVerify() {
         verify(null);
diff --git a/src/test/java/org/mockitousage/misuse/DetectingMisusedMatchersTest.java b/src/test/java/org/mockitousage/misuse/DetectingMisusedMatchersTest.java
index 7bf1896..267e93c 100644
--- a/src/test/java/org/mockitousage/misuse/DetectingMisusedMatchersTest.java
+++ b/src/test/java/org/mockitousage/misuse/DetectingMisusedMatchersTest.java
@@ -83,6 +83,7 @@
     }
 
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test
     public void shouldSayUnfinishedVerificationButNotInvalidUseOfMatchers() {
         assumeTrue("Does not apply for inline mocks", withFinal.getClass() != WithFinal.class);
diff --git a/src/test/java/org/mockitousage/misuse/ExplicitFrameworkValidationTest.java b/src/test/java/org/mockitousage/misuse/ExplicitFrameworkValidationTest.java
index 0fcb41c..9ebc690 100644
--- a/src/test/java/org/mockitousage/misuse/ExplicitFrameworkValidationTest.java
+++ b/src/test/java/org/mockitousage/misuse/ExplicitFrameworkValidationTest.java
@@ -23,6 +23,7 @@
 
     @Mock IMethods mock;
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test
     public void shouldValidateExplicitly() {
         verify(mock);
@@ -32,6 +33,7 @@
         } catch (UnfinishedVerificationException e) {}
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test
     public void shouldDetectUnfinishedStubbing() {
         when(mock.simpleMethod());
diff --git a/src/test/java/org/mockitousage/misuse/InvalidUsageTest.java b/src/test/java/org/mockitousage/misuse/InvalidUsageTest.java
index ff3ca09..2197300 100644
--- a/src/test/java/org/mockitousage/misuse/InvalidUsageTest.java
+++ b/src/test/java/org/mockitousage/misuse/InvalidUsageTest.java
@@ -37,6 +37,7 @@
         verifyZeroInteractions();
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test(expected=MockitoException.class)
     public void shouldNotCreateInOrderObjectWithoutMocks() {
         inOrder();
@@ -82,6 +83,7 @@
         assumeFalse("Inlining mock allows mocking final classes", mock(FinalClass.class).getClass() == FinalClass.class);
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test(expected=MockitoException.class)
     public void shouldNotAllowMockingPrimitives() throws Exception {
         mock(Integer.TYPE);
@@ -104,6 +106,7 @@
         verifyZeroInteractions(inter);
     }
 
+    @Test
     public void shouldNotMockObjectMethodsOnClass() throws Exception {
         Object clazz = mock(ObjectLikeInterface.class);
 
diff --git a/src/test/java/org/mockitousage/packageprotected/MockingPackageProtectedTest.java b/src/test/java/org/mockitousage/packageprotected/MockingPackageProtectedTest.java
index b06d073..b740508 100644
--- a/src/test/java/org/mockitousage/packageprotected/MockingPackageProtectedTest.java
+++ b/src/test/java/org/mockitousage/packageprotected/MockingPackageProtectedTest.java
@@ -16,6 +16,7 @@
 
     class Bar {}
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldMockPackageProtectedClasses() {
         mock(PackageProtected.class);
diff --git a/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java b/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
index 1f12cdf..3294614 100644
--- a/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
+++ b/src/test/java/org/mockitousage/serialization/DeepStubsSerializableTest.java
@@ -59,31 +59,56 @@
         // then revert to the default RETURNS_DEEP_STUBS and the code will raise a ClassCastException
     }
 
-
     static class SampleClass implements Serializable {
-        SampleClass2 getSample() { return new SampleClass2(); }
+
+        SampleClass2 getSample() {
+            return new SampleClass2();
+        }
     }
 
     static class SampleClass2 implements Serializable {
-        boolean isFalse() { return false; }
-        int number() { return 100; }
+
+        boolean isFalse() {
+            return false;
+        }
+
+        int number() {
+            return 100;
+        }
     }
 
     static class Container<E> implements Iterable<E>, Serializable {
+
         private E e;
-        public Container(E e) { this.e = e; }
-        public E get() { return e; }
+
+        public Container(E e) {
+            this.e = e;
+        }
+
+        public E get() {
+            return e;
+        }
 
         public Iterator<E> iterator() {
             return new Iterator<E>() {
-                public boolean hasNext() { return true; }
-                public E next() { return e; }
-                public void remove() { }
+                public boolean hasNext() {
+                    return true;
+                }
+
+                public E next() {
+                    return e;
+                }
+
+                public void remove() {
+                }
             };
         }
     }
 
     static class ListContainer extends Container<List<String>> {
-        public ListContainer(List<String> list) { super(list); }
+
+        public ListContainer(List<String> list) {
+            super(list);
+        }
     }
 }
diff --git a/src/test/java/org/mockitousage/session/MockitoSessionTest.java b/src/test/java/org/mockitousage/session/MockitoSessionTest.java
index 960d888..a87928c 100644
--- a/src/test/java/org/mockitousage/session/MockitoSessionTest.java
+++ b/src/test/java/org/mockitousage/session/MockitoSessionTest.java
@@ -151,6 +151,7 @@
             mockito.finishMocking();
         }
 
+        @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
         @Test public void unfinished_stubbing() {
             when(mock.simpleMethod());
         }
@@ -165,6 +166,7 @@
             mockito.finishMocking();
         }
 
+        @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
         @Test public void unfinished_stubbing_with_other_failure() {
             when(mock.simpleMethod());
             assertTrue(false);
@@ -214,6 +216,7 @@
             mockito.finishMocking(new RuntimeException("Boo!"));
         }
 
+        @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
         @Test public void invalid_mockito_usage() {
             verify(mock);
         }
diff --git a/src/test/java/org/mockitousage/spies/SpyingOnRealObjectsTest.java b/src/test/java/org/mockitousage/spies/SpyingOnRealObjectsTest.java
index f67c623..8603ca0 100644
--- a/src/test/java/org/mockitousage/spies/SpyingOnRealObjectsTest.java
+++ b/src/test/java/org/mockitousage/spies/SpyingOnRealObjectsTest.java
@@ -40,6 +40,7 @@
         verify(spy).add("two");
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldBeAbleToMockObjectBecauseWhyNot() {
         spy(new Object());
diff --git a/src/test/java/org/mockitousage/stacktrace/ClickableStackTracesWhenFrameworkMisusedTest.java b/src/test/java/org/mockitousage/stacktrace/ClickableStackTracesWhenFrameworkMisusedTest.java
index bdefa14..e9a98c1 100644
--- a/src/test/java/org/mockitousage/stacktrace/ClickableStackTracesWhenFrameworkMisusedTest.java
+++ b/src/test/java/org/mockitousage/stacktrace/ClickableStackTracesWhenFrameworkMisusedTest.java
@@ -44,6 +44,7 @@
         }
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     private void unfinishedStubbingHere() {
         when(mock.simpleMethod());
     }
@@ -73,6 +74,7 @@
         }
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     private void unfinishedVerificationHere() {
         verify(mock);
     }
diff --git a/src/test/java/org/mockitousage/stacktrace/ModellingDescriptiveMessagesTest.java b/src/test/java/org/mockitousage/stacktrace/ModellingDescriptiveMessagesTest.java
index a09ee71..e1bd9af 100644
--- a/src/test/java/org/mockitousage/stacktrace/ModellingDescriptiveMessagesTest.java
+++ b/src/test/java/org/mockitousage/stacktrace/ModellingDescriptiveMessagesTest.java
@@ -32,6 +32,7 @@
         super.makeStackTracesClean();
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test
     public void makeSureStateIsValidatedInTheVeryFirstTestThanksToTheRunner() {
         //mess up the state:
@@ -137,6 +138,7 @@
         m.simpleMethod();
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test
     public void shouldPointOutUnfinishedStubbing() {
         when(mock.simpleMethod());
@@ -167,26 +169,31 @@
         argument.getValue();
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldScreamWhenNullPassedInsteadOfAnInterface() {
         mock(IMethods.class, withSettings().extraInterfaces(List.class, null));
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldScreamWhenNonInterfacePassed() {
         mock(IMethods.class, withSettings().extraInterfaces(LinkedList.class));
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldScreamWhenExtraIsTheSame() {
         mock(IMethods.class, withSettings().extraInterfaces(IMethods.class));
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldScreamWhenExtraInterfacesEmpty() {
         mock(IMethods.class, withSettings().extraInterfaces());
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void shouldScreamWhenExtraInterfacesIsANullArray() {
         mock(IMethods.class, withSettings().extraInterfaces((Class<?>[]) null));
diff --git a/src/test/java/org/mockitousage/stacktrace/StackTraceFilteringTest.java b/src/test/java/org/mockitousage/stacktrace/StackTraceFilteringTest.java
index 23f6033..6186130 100644
--- a/src/test/java/org/mockitousage/stacktrace/StackTraceFilteringTest.java
+++ b/src/test/java/org/mockitousage/stacktrace/StackTraceFilteringTest.java
@@ -72,6 +72,7 @@
         }
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test
     public void shouldFilterStacktraceOnMockitoException() {
         verify(mock);
diff --git a/src/test/java/org/mockitousage/strictness/StrictnessPerMockTest.java b/src/test/java/org/mockitousage/strictness/StrictnessPerMockTest.java
new file mode 100644
index 0000000..2dce3e0
--- /dev/null
+++ b/src/test/java/org/mockitousage/strictness/StrictnessPerMockTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.Assertions;
+import org.assertj.core.api.ThrowableAssert;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+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 junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertNull;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockingDetails;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.withSettings;
+
+//TODO 792 also move other Strictness tests to this package (unless they already have good package)
+public class StrictnessPerMockTest {
+
+    MockitoSession mockito;
+    @Mock IMethods strictStubsMock;
+    IMethods lenientMock;
+
+    @Before
+    public void before() {
+        mockito = Mockito.mockitoSession().initMocks(this).strictness(Strictness.STRICT_STUBS).startMocking();
+        assertNull(lenientMock);
+        lenientMock = mock(IMethods.class, withSettings().lenient());
+    }
+
+    @Test
+    public void knows_if_mock_is_lenient() {
+        assertTrue(mockingDetails(lenientMock).getMockCreationSettings().isLenient());
+        assertFalse(mockingDetails(strictStubsMock).getMockCreationSettings().isLenient());
+    }
+
+    @Test
+    public void potential_stubbing_problem() {
+        //when
+        given(lenientMock.simpleMethod(100)).willReturn("100");
+        given(strictStubsMock.simpleMethod(100)).willReturn("100");
+
+        //then on lenient mock (created by hand), we can call the stubbed method with different arg:
+        lenientMock.simpleMethod(200);
+
+        //and on strict stub mock (created by session), we cannot call stubbed method with different arg:
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() throws Throwable {
+                strictStubsMock.simpleMethod(200);
+            }
+        }).isInstanceOf(PotentialStubbingProblem.class);
+    }
+
+    @Test
+    public void unnecessary_stubbing() {
+        //when
+        given(lenientMock.simpleMethod(100)).willReturn("100");
+        given(strictStubsMock.simpleMethod(100)).willReturn("100");
+
+        //then unnecessary stubbing flags method only on the strict stub mock:
+        Assertions.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: let's make UnnecessaryStubbingException exception contain the Invocation instance
+            //so that we can write clean assertion rather than depending on string
+            .isNot(TestBase.hasMessageContaining("2. ->"));
+    }
+
+    @Test
+    public void verify_no_more_invocations() {
+        //when
+        given(lenientMock.simpleMethod(100)).willReturn("100");
+        given(strictStubsMock.simpleMethod(100)).willReturn("100");
+
+        //and:
+        strictStubsMock.simpleMethod(100);
+        lenientMock.simpleMethod(100);
+
+        //then 'verifyNoMoreInteractions' ignores strict stub (implicitly verified) but flags the lenient mock
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() throws Throwable {
+                verifyNoMoreInteractions(strictStubsMock, lenientMock);
+            }
+        }).isInstanceOf(NoInteractionsWanted.class)
+            .hasMessageContaining("But found this interaction on mock 'iMethods'")
+            //TODO 792: let's make NoInteractionsWanted exception contain the Invocation instances
+            //so that we can write clean assertion rather than depending on string
+            .hasMessageContaining("Actually, above is the only interaction with this mock");
+    }
+
+    @After
+    public void after() {
+        mockito.finishMocking();
+    }
+}
diff --git a/src/test/java/org/mockitousage/strictness/StrictnessPerStubbingTest.java b/src/test/java/org/mockitousage/strictness/StrictnessPerStubbingTest.java
new file mode 100644
index 0000000..3838bee
--- /dev/null
+++ b/src/test/java/org/mockitousage/strictness/StrictnessPerStubbingTest.java
@@ -0,0 +1,271 @@
+/*
+ * 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();
+    }
+}
diff --git a/src/test/java/org/mockitousage/strictness/StrictnessPerStubbingWithRunnerTest.java b/src/test/java/org/mockitousage/strictness/StrictnessPerStubbingWithRunnerTest.java
new file mode 100644
index 0000000..e42d340
--- /dev/null
+++ b/src/test/java/org/mockitousage/strictness/StrictnessPerStubbingWithRunnerTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.exceptions.misusing.PotentialStubbingProblem;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockitousage.IMethods;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class StrictnessPerStubbingWithRunnerTest {
+
+    @Mock IMethods mock;
+
+    @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);
+
+        //let's use the strict stubbing so that it is not reported as failure by the runner:
+        mock.simpleMethod("1");
+    }
+
+    @Test
+    public void unnecessary_stubbing() {
+        //this unnecessary stubbing is not flagged by the runner:
+        lenient().when(mock.differentMethod("2")).thenReturn("2");
+    }
+}
diff --git a/src/test/java/org/mockitousage/strictness/StrictnessWhenRuleStrictnessIsUpdatedTest.java b/src/test/java/org/mockitousage/strictness/StrictnessWhenRuleStrictnessIsUpdatedTest.java
new file mode 100644
index 0000000..592cca9
--- /dev/null
+++ b/src/test/java/org/mockitousage/strictness/StrictnessWhenRuleStrictnessIsUpdatedTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.exceptions.misusing.PotentialStubbingProblem;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+import org.mockitousage.IMethods;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+public class StrictnessWhenRuleStrictnessIsUpdatedTest {
+
+    @Mock IMethods mock;
+    @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.LENIENT);
+
+    @Test
+    public void strictness_per_mock() {
+        //when
+        rule.strictness(Strictness.STRICT_STUBS);
+
+        //then previous mock is strict:
+        when(mock.simpleMethod(1)).thenReturn("1");
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() throws Throwable {
+                mock.simpleMethod(2);
+            }
+        }).isInstanceOf(PotentialStubbingProblem.class);
+
+        //but the new mock is lenient, even though the rule is not:
+        final IMethods lenientMock = mock(IMethods.class, withSettings().lenient());
+        when(lenientMock.simpleMethod(1)).thenReturn("1");
+        lenientMock.simpleMethod(100);
+    }
+
+    @Test
+    public void strictness_per_stubbing() {
+        //when
+        rule.strictness(Strictness.STRICT_STUBS);
+
+        //then previous mock is strict:
+        when(mock.simpleMethod(1)).thenReturn("1");
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() throws Throwable {
+                mock.simpleMethod(2);
+            }
+        }).isInstanceOf(PotentialStubbingProblem.class);
+
+        //but the new mock is lenient, even though the rule is not:
+        lenient().when(mock.simpleMethod(1)).thenReturn("1");
+        mock.simpleMethod(100);
+    }
+}
diff --git a/src/test/java/org/mockitousage/strictness/StrictnessWithRulesTest.java b/src/test/java/org/mockitousage/strictness/StrictnessWithRulesTest.java
new file mode 100644
index 0000000..3a323fb
--- /dev/null
+++ b/src/test/java/org/mockitousage/strictness/StrictnessWithRulesTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.exceptions.misusing.PotentialStubbingProblem;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+import org.mockitousage.IMethods;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.when;
+
+public class StrictnessWithRulesTest {
+
+    @Mock IMethods mock;
+    @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+
+    @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);
+
+        //let's use the strict stubbing so that it is not reported as failure by the rule:
+        mock.simpleMethod("1");
+    }
+
+    @Test
+    public void unnecessary_stubbing() {
+        //this unnecessary stubbing is not flagged by the rule:
+        lenient().when(mock.differentMethod("2")).thenReturn("2");
+    }
+}
diff --git a/src/test/java/org/mockitousage/stubbing/BasicStubbingTest.java b/src/test/java/org/mockitousage/stubbing/BasicStubbingTest.java
index 4dd9d8f..c63cb6d 100644
--- a/src/test/java/org/mockitousage/stubbing/BasicStubbingTest.java
+++ b/src/test/java/org/mockitousage/stubbing/BasicStubbingTest.java
@@ -93,6 +93,7 @@
         }
     }
 
+    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
     @Test
     public void should_allow_mocking_when_to_string_is_final() throws Exception {
         mock(Foo.class);
@@ -114,4 +115,15 @@
             fail();
         } catch (CannotVerifyStubOnlyMock e) {}
     }
+
+    @SuppressWarnings("MockitoUsage")
+    @Test
+    public void test_stub_only_not_verifiable_fail_fast() {
+        IMethods localMock = mock(IMethods.class, withSettings().stubOnly());
+
+        try {
+            verify(localMock); // throws exception before method invocation
+            fail();
+        } catch (CannotVerifyStubOnlyMock e) {}
+    }
 }
diff --git a/src/test/java/org/mockitousage/stubbing/StubbingConsecutiveAnswersTest.java b/src/test/java/org/mockitousage/stubbing/StubbingConsecutiveAnswersTest.java
index f8fa2b5..47c2172 100644
--- a/src/test/java/org/mockitousage/stubbing/StubbingConsecutiveAnswersTest.java
+++ b/src/test/java/org/mockitousage/stubbing/StubbingConsecutiveAnswersTest.java
@@ -42,6 +42,34 @@
     }
 
     @Test
+    public void should_return_consecutive_values_first_var_arg_null() throws Exception {
+        when(mock.simpleMethod()).thenReturn("one", (String) null);
+
+        assertEquals("one", mock.simpleMethod());
+        assertNull(mock.simpleMethod());
+        assertNull(mock.simpleMethod());
+    }
+
+    @Test
+    public void should_return_consecutive_values_var_arg_null() throws Exception {
+        when(mock.simpleMethod()).thenReturn("one", (String[]) null);
+
+        assertEquals("one", mock.simpleMethod());
+        assertNull(mock.simpleMethod());
+        assertNull(mock.simpleMethod());
+    }
+
+    @Test
+    public void should_return_consecutive_values_var_args_contain_null() throws Exception {
+        when(mock.simpleMethod()).thenReturn("one", "two", null);
+
+        assertEquals("one", mock.simpleMethod());
+        assertEquals("two", mock.simpleMethod());
+        assertNull(mock.simpleMethod());
+        assertNull(mock.simpleMethod());
+    }
+
+    @Test
     public void should_return_consecutive_values_set_by_shorten_then_return_method() throws Exception {
         when(mock.simpleMethod()).thenReturn("one", "two", "three");
 
diff --git a/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java b/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java
index 754b7dc..6bf2041 100644
--- a/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java
+++ b/src/test/java/org/mockitousage/stubbing/StubbingWarningsTest.java
@@ -96,6 +96,7 @@
                 filterLineNo(logger.getLoggedInfo()));
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test(expected = MockitoException.class) public void unfinished_verification_without_throwable() throws Throwable {
         //when
         verify(mock);
@@ -103,6 +104,7 @@
         mockito.finishMocking();
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test public void unfinished_verification_with_throwable() throws Throwable {
         //when
         verify(mock);
diff --git a/src/test/java/org/mockitousage/stubbing/StubbingWithDelegateTest.java b/src/test/java/org/mockitousage/stubbing/StubbingWithDelegateTest.java
index 885e78e..24c4854 100644
--- a/src/test/java/org/mockitousage/stubbing/StubbingWithDelegateTest.java
+++ b/src/test/java/org/mockitousage/stubbing/StubbingWithDelegateTest.java
@@ -111,7 +111,7 @@
         List<String> mock = mock(List.class, delegatesTo(new FakeList<String>()));
 
         mock.set(1, "1");
-        assertThat(mock.get(1).equals("1"));
+        assertThat(mock.get(1).equals("1")).isTrue();
     }
 
     @Test
@@ -119,7 +119,7 @@
         List<String> mock = mock(List.class, delegatesTo(new FakeList<String>()));
 
         List<String> subList = mock.subList(0, 0);
-        assertThat(subList.isEmpty());
+        assertThat(subList.isEmpty()).isTrue();
     }
 
     @Test
diff --git a/src/test/java/org/mockitousage/stubbing/StubbingWithThrowablesTest.java b/src/test/java/org/mockitousage/stubbing/StubbingWithThrowablesTest.java
index 9f526bf..9353724 100644
--- a/src/test/java/org/mockitousage/stubbing/StubbingWithThrowablesTest.java
+++ b/src/test/java/org/mockitousage/stubbing/StubbingWithThrowablesTest.java
@@ -22,6 +22,9 @@
 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;
@@ -49,13 +52,54 @@
     }
 
     @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
diff --git a/src/test/java/org/mockitousage/verification/AtMostXVerificationTest.java b/src/test/java/org/mockitousage/verification/AtMostXVerificationTest.java
index 04cb32a..2756ef8 100644
--- a/src/test/java/org/mockitousage/verification/AtMostXVerificationTest.java
+++ b/src/test/java/org/mockitousage/verification/AtMostXVerificationTest.java
@@ -8,17 +8,21 @@
 import org.junit.Test;
 import org.mockito.InOrder;
 import org.mockito.Mock;
-import org.mockito.exceptions.base.MockitoAssertionError;
 import org.mockito.exceptions.base.MockitoException;
+import org.mockito.exceptions.verification.MoreThanAllowedActualInvocations;
 import org.mockito.exceptions.verification.NoInteractionsWanted;
 import org.mockitoutil.TestBase;
 
 import java.util.List;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 public class AtMostXVerificationTest extends TestBase {
 
@@ -35,7 +39,7 @@
         try {
             verify(mock, atMost(1)).clear();
             fail();
-        } catch (MockitoAssertionError e) {}
+        } catch (MoreThanAllowedActualInvocations e) {}
     }
 
     @Test
@@ -46,7 +50,7 @@
         try {
             verify(mock, atMost(0)).add(anyString());
             fail();
-        } catch (MockitoAssertionError e) {}
+        } catch (MoreThanAllowedActualInvocations e) {}
     }
 
     @Test
@@ -67,7 +71,7 @@
         try {
             verify(mock, atMost(1)).clear();
             fail();
-        } catch (MockitoAssertionError e) {
+        } catch (MoreThanAllowedActualInvocations e) {
             assertEquals("\nWanted at most 1 time but was 2", e.getMessage());
         }
     }
diff --git a/src/test/java/org/mockitousage/verification/BasicVerificationInOrderTest.java b/src/test/java/org/mockitousage/verification/BasicVerificationInOrderTest.java
index ccf3570..b0e3179 100644
--- a/src/test/java/org/mockitousage/verification/BasicVerificationInOrderTest.java
+++ b/src/test/java/org/mockitousage/verification/BasicVerificationInOrderTest.java
@@ -264,7 +264,7 @@
         verifyZeroInteractions(mockOne);
     }
 
-    @SuppressWarnings("all")
+    @SuppressWarnings({"all", "CheckReturnValue", "MockitoUsage"})
     @Test(expected = MockitoException.class)
     public void shouldScreamWhenNullPassed() {
         inOrder((Object[])null);
diff --git a/src/test/java/org/mockitousage/verification/BasicVerificationTest.java b/src/test/java/org/mockitousage/verification/BasicVerificationTest.java
index aa350cf..d9a74ff 100644
--- a/src/test/java/org/mockitousage/verification/BasicVerificationTest.java
+++ b/src/test/java/org/mockitousage/verification/BasicVerificationTest.java
@@ -5,16 +5,19 @@
 
 package org.mockitousage.verification;
 
+import org.assertj.core.api.ThrowableAssert;
 import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.exceptions.verification.NoInteractionsWanted;
 import org.mockito.exceptions.verification.TooManyActualInvocations;
 import org.mockito.exceptions.verification.WantedButNotInvoked;
+import org.mockito.exceptions.verification.junit.ArgumentsAreDifferent;
 import org.mockitousage.IMethods;
 import org.mockitoutil.TestBase;
 
 import java.util.List;
 
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.*;
 
@@ -45,10 +48,13 @@
         mock.add("foo");
 
         verify(mock).clear();
-        try {
-            verify(mock).add("bar");
-            fail();
-        } catch (AssertionError expected) {}
+
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock).add("bar");
+            }
+        }).isInstanceOf(ArgumentsAreDifferent.class);
     }
 
     @Test
diff --git a/src/test/java/org/mockitousage/verification/DelayedExecution.java b/src/test/java/org/mockitousage/verification/DelayedExecution.java
deleted file mode 100644
index a34b546..0000000
--- a/src/test/java/org/mockitousage/verification/DelayedExecution.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2017 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockitousage.verification;
-
-import static java.lang.System.currentTimeMillis;
-import static java.lang.Thread.MAX_PRIORITY;
-import static java.util.concurrent.Executors.newScheduledThreadPool;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static java.util.concurrent.locks.LockSupport.parkUntil;
-
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-
-class DelayedExecution {
-    private static final int CORE_POOL_SIZE = 3;
-    /**
-     * Defines the number of milliseconds we expecting a Thread might need to unpark, we use this to avoid "oversleeping" while awaiting the deadline for
-     */
-    private static final long MAX_EXPECTED_OVERSLEEP_MILLIS = 50;
-
-    private final ScheduledExecutorService executor;
-
-    public DelayedExecution() {
-        this.executor = newScheduledThreadPool(CORE_POOL_SIZE, maxPrioThreadFactory());
-    }
-
-    public void callAsync(long delay, TimeUnit timeUnit, Runnable r) {
-        long deadline = timeUnit.toMillis(delay) + currentTimeMillis();
-
-        executor.submit(delayedExecution(r, deadline));
-    }
-
-    public void close() throws InterruptedException {
-        executor.shutdownNow();
-
-        if (!executor.awaitTermination(5, SECONDS)) {
-            throw new IllegalStateException("This delayed execution did not terminated after 5 seconds");
-        }
-    }
-
-    private static Runnable delayedExecution(final Runnable r, final long deadline) {
-        return new Runnable() {
-            @Override
-            public void run() {
-                //we park the current Thread till 50ms before we want to execute the runnable
-                parkUntil(deadline - MAX_EXPECTED_OVERSLEEP_MILLIS);
-                //now we closing to the deadline by burning CPU-time in a loop
-                burnRemaining(deadline);
-
-                System.out.println("[DelayedExecution] exec delay = "+(currentTimeMillis() - deadline)+"ms");
-
-                r.run();
-            }
-
-            /**
-             * Loop in tight cycles until we reach the dead line. We do this cause sleep or park is very not precise,
-             * this can causes a Thread to under- or oversleep, sometimes by +50ms.
-             */
-            private void burnRemaining(final long deadline) {
-                long remaining;
-                do {
-                    remaining = deadline - currentTimeMillis();
-                } while (remaining > 0);
-            }
-        };
-    }
-
-    private static ThreadFactory maxPrioThreadFactory() {
-        return new ThreadFactory() {
-            @Override
-            public Thread newThread(Runnable r) {
-                Thread t = new Thread(r);
-                t.setDaemon(true);  // allows the JVM to exit when clients forget to call DelayedExecution.close()
-                t.setPriority(MAX_PRIORITY);
-                return t;
-            }
-        };
-    }
-}
diff --git a/src/test/java/org/mockitousage/verification/DescriptiveMessagesOnVerificationInOrderErrorsTest.java b/src/test/java/org/mockitousage/verification/DescriptiveMessagesOnVerificationInOrderErrorsTest.java
index 4e5f464..8e1bf06 100644
--- a/src/test/java/org/mockitousage/verification/DescriptiveMessagesOnVerificationInOrderErrorsTest.java
+++ b/src/test/java/org/mockitousage/verification/DescriptiveMessagesOnVerificationInOrderErrorsTest.java
@@ -155,7 +155,7 @@
 
             String expectedCause =
                 "\n" +
-                "But was 2 times. Undesired invocation:" +
+                "But was 2 times:" +
                 "\n" +
                 "-> at";
             assertThat(e).hasMessageContaining(expectedCause);
diff --git a/src/test/java/org/mockitousage/verification/FindingRedundantInvocationsInOrderTest.java b/src/test/java/org/mockitousage/verification/FindingRedundantInvocationsInOrderTest.java
index 0dffbfa..271d95c 100644
--- a/src/test/java/org/mockitousage/verification/FindingRedundantInvocationsInOrderTest.java
+++ b/src/test/java/org/mockitousage/verification/FindingRedundantInvocationsInOrderTest.java
@@ -107,6 +107,7 @@
         } catch(VerificationInOrderFailure e) {}
     }
 
+    @SuppressWarnings({"MockitoUsage", "CheckReturnValue"})
     @Test
     public void shouldValidateState() throws Exception {
         //when
diff --git a/src/test/java/org/mockitousage/verification/VerificationAfterDelayTest.java b/src/test/java/org/mockitousage/verification/VerificationAfterDelayTest.java
deleted file mode 100644
index f0e42ee..0000000
--- a/src/test/java/org/mockitousage/verification/VerificationAfterDelayTest.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2007 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-
-package org.mockitousage.verification;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.exceptions.base.MockitoAssertionError;
-import org.mockito.junit.MockitoRule;
-import org.mockitousage.IMethods;
-import org.mockitoutil.RetryRule;
-import org.mockitoutil.Stopwatch;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.junit.Assert.assertEquals;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.junit.rules.ExpectedException.none;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.junit.MockitoJUnit.rule;
-import static org.mockitoutil.Stopwatch.createNotStarted;
-
-public class VerificationAfterDelayTest {
-
-    @Rule
-    public MockitoRule mockito = rule();
-
-    @Rule
-    public RetryRule retryRule = RetryRule.attempts(4);
-
-    @Rule
-    public ExpectedException exception = none();
-
-    @Mock
-    private IMethods mock;
-
-    @Captor
-    private ArgumentCaptor<Character> captor;
-
-    private Stopwatch stopWatch;
-
-    private DelayedExecution delayedExecution;
-
-    private Runnable callMock = new Runnable() {
-        @Override
-        public void run() {
-            mock.oneArg('1');
-        }
-    };
-
-    @Before
-    public void setUp() {
-        delayedExecution = new DelayedExecution();
-        stopWatch = createNotStarted();
-    }
-
-    @After
-    public void tearDown() throws InterruptedException {
-        delayedExecution.close();
-    }
-
-    @Test
-    public void shouldVerifyNormallyWithSpecificTimes() throws Exception {
-        // given
-        delayedExecution.callAsync(30, MILLISECONDS, callMock );
-
-        // then
-        verify(mock, after(100).times(1)).oneArg('1');
-    }
-
-    @Test
-    public void shouldVerifyNormallyWithAtLeast() throws Exception {
-        // when
-        delayedExecution.callAsync(30, MILLISECONDS, callMock );
-
-        // then
-        verify(mock, after(100).atLeast(1)).oneArg('1');
-    }
-
-    @Test
-    public void shouldFailVerificationWithWrongTimes() throws Exception {
-        // when
-        delayedExecution.callAsync(30, MILLISECONDS, callMock );
-
-        // then
-        verify(mock, times(0)).oneArg('1');
-        exception.expect(MockitoAssertionError.class);
-        verify(mock, after(100).times(2)).oneArg('1');
-    }
-
-    @Test
-    public void shouldWaitTheFullTimeIfTheTestCouldPass() throws Exception {
-        // when
-        delayedExecution.callAsync(30, MILLISECONDS, callMock );
-
-        // then
-        stopWatch.start();
-
-        try {
-            verify(mock, after(100).atLeast(2)).oneArg('1');
-            fail("Expected behavior was to throw an exception, and never reach this line");
-        } catch (MockitoAssertionError ignored) {
-        }
-
-        stopWatch.assertElapsedTimeIsMoreThan(100, MILLISECONDS);
-    }
-
-    @Test
-    public void shouldStopEarlyIfTestIsDefinitelyFailed() throws Exception {
-        // when
-        delayedExecution.callAsync(30, MILLISECONDS, callMock );
-
-        // then
-        exception.expect(MockitoAssertionError.class);
-        verify(mock, after(10000).never()).oneArg('1');
-    }
-
-    /**
-     * Test for issue #345.
-     */
-    @Test
-    public void shouldReturnListOfArgumentsWithSameSizeAsGivenInAtMostVerification() {
-        // given
-        int n = 3;
-
-        // when
-        exerciseMockNTimes(n);
-
-        stopWatch.start();
-        // then
-        verify(mock, after(200).atMost(n)).oneArg((char) captor.capture());
-
-        stopWatch.assertElapsedTimeIsMoreThan(200, MILLISECONDS);
-        assertThat(captor.getAllValues()).containsExactly('0', '1', '2');
-    }
-
-    @Test
-    public void shouldReturnListOfArgumentsWithSameSizeAsGivenInTimesVerification() {
-        // given
-        int n = 3;
-
-        // when
-        exerciseMockNTimes(n);
-
-        //Then
-        verify(mock, after(200).times(n)).oneArg((char) captor.capture());
-        assertEquals(n, captor.getAllValues().size());
-        assertEquals('0', (char) captor.getAllValues().get(0));
-        assertEquals('1', (char) captor.getAllValues().get(1));
-        assertEquals('2', (char) captor.getAllValues().get(2));
-    }
-
-    @Test
-    public void shouldReturnListOfArgumentsWithSameSizeAsGivenInAtLeastVerification() {
-        // given
-        int n = 3;
-
-        // when
-        exerciseMockNTimes(n);
-
-        //Then
-        verify(mock, after(200).atLeast(n)).oneArg((char) captor.capture());
-        assertEquals(n, captor.getAllValues().size());
-        assertEquals('0', (char) captor.getAllValues().get(0));
-        assertEquals('1', (char) captor.getAllValues().get(1));
-        assertEquals('2', (char) captor.getAllValues().get(2));
-    }
-
-    private void exerciseMockNTimes(int n) {
-        for (int i = 0; i < n; i++) {
-            mock.oneArg((char) ('0' + i));
-        }
-    }
-
-}
diff --git a/src/test/java/org/mockitousage/verification/VerificationWithAfterAndCaptorTest.java b/src/test/java/org/mockitousage/verification/VerificationWithAfterAndCaptorTest.java
new file mode 100644
index 0000000..1f11319
--- /dev/null
+++ b/src/test/java/org/mockitousage/verification/VerificationWithAfterAndCaptorTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockitousage.verification;
+
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoRule;
+import org.mockitousage.IMethods;
+import org.mockitoutil.Stopwatch;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.verify;
+import static org.mockito.junit.MockitoJUnit.rule;
+import static org.mockitoutil.Stopwatch.createNotStarted;
+
+public class VerificationWithAfterAndCaptorTest {
+
+    @Rule public MockitoRule mockito = rule();
+
+    @Mock private IMethods mock;
+
+    @Captor private ArgumentCaptor<Character> captor;
+
+    private Stopwatch watch = createNotStarted();
+
+    /**
+     * Test for issue #345.
+     */
+    @Test
+    public void shouldReturnListOfArgumentsWithSameSizeAsGivenInAtMostVerification() {
+        // given
+        int n = 3;
+
+        // when
+        exerciseMockNTimes(n);
+
+        watch.start();
+
+        // then
+        verify(mock, after(200).atMost(n)).oneArg((char) captor.capture());
+
+        watch.assertElapsedTimeIsMoreThan(200, MILLISECONDS);
+        assertThat(captor.getAllValues()).containsExactly('0', '1', '2');
+    }
+
+    @Test
+    @Ignore("TODO review after #936")
+    public void shouldReturnListOfArgumentsWithSameSizeAsGivenInTimesVerification() {
+        // given
+        int n = 3;
+
+        // when
+        exerciseMockNTimes(n);
+
+        //Then
+        verify(mock, after(200).times(n)).oneArg((char) captor.capture());
+        assertEquals(n, captor.getAllValues().size());
+        assertEquals('0', (char) captor.getAllValues().get(0));
+        assertEquals('1', (char) captor.getAllValues().get(1));
+        assertEquals('2', (char) captor.getAllValues().get(2));
+    }
+
+    @Test
+    @Ignore("TODO review after #936")
+    public void shouldReturnListOfArgumentsWithSameSizeAsGivenInAtLeastVerification() {
+        // given
+        int n = 3;
+
+        // when
+        exerciseMockNTimes(n);
+
+        //Then
+        verify(mock, after(200).atLeast(n)).oneArg((char) captor.capture());
+        assertEquals(n, captor.getAllValues().size());
+        assertEquals('0', (char) captor.getAllValues().get(0));
+        assertEquals('1', (char) captor.getAllValues().get(1));
+        assertEquals('2', (char) captor.getAllValues().get(2));
+    }
+
+    private void exerciseMockNTimes(int n) {
+        for (int i = 0; i < n; i++) {
+            mock.oneArg((char) ('0' + i));
+        }
+    }
+}
diff --git a/src/test/java/org/mockitousage/verification/VerificationWithAfterTest.java b/src/test/java/org/mockitousage/verification/VerificationWithAfterTest.java
new file mode 100644
index 0000000..f437c03
--- /dev/null
+++ b/src/test/java/org/mockitousage/verification/VerificationWithAfterTest.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2007 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockitousage.verification;
+
+import org.assertj.core.api.Assertions;
+import org.assertj.core.api.ThrowableAssert;
+import org.junit.After;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.exceptions.verification.MoreThanAllowedActualInvocations;
+import org.mockito.exceptions.verification.NoInteractionsWanted;
+import org.mockito.exceptions.verification.TooManyActualInvocations;
+import org.mockito.junit.MockitoRule;
+import org.mockitousage.IMethods;
+import org.mockitoutil.Stopwatch;
+import org.mockitoutil.async.AsyncTesting;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.verify;
+import static org.mockito.junit.MockitoJUnit.rule;
+import static org.mockitoutil.Stopwatch.createNotStarted;
+
+public class VerificationWithAfterTest {
+
+    @Rule public MockitoRule mockito = rule();
+
+    @Mock private IMethods mock;
+
+    private Runnable callMock = new Runnable() {
+        public void run() {
+            mock.oneArg('1');
+        }
+    };
+
+    private AsyncTesting async = new AsyncTesting();
+    private Stopwatch watch = createNotStarted();
+
+    @After public void tearDown() {
+        async.cleanUp();
+    }
+
+    @Test
+    public void should_verify_with_after() {
+        // given
+        async.runAfter(10, callMock);
+        async.runAfter(1000, callMock);
+
+        // then
+        verify(mock, after(300)).oneArg('1');
+    }
+
+    @Test
+    public void should_verify_with_after_and_fail() {
+        // given
+        async.runAfter(10, callMock);
+        async.runAfter(40, callMock);
+
+        // then
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, after(300)).oneArg('1');
+            }
+        }).isInstanceOf(TooManyActualInvocations.class);
+    }
+
+    @Test
+    public void should_verify_with_time_x() {
+        // given
+        async.runAfter(10, callMock);
+        async.runAfter(50, callMock);
+        async.runAfter(600, callMock);
+
+        // then
+        verify(mock, after(300).times(2)).oneArg('1');
+    }
+
+    @Test
+    public void should_verify_with_time_x_and_fail() {
+        // given
+        async.runAfter(10, callMock);
+        async.runAfter(40, callMock);
+        async.runAfter(80, callMock);
+
+        // then
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, after(300).times(2)).oneArg('1');
+            }
+        }).isInstanceOf(TooManyActualInvocations.class);
+    }
+
+    @Test
+    public void should_verify_with_at_least() {
+        // given
+        async.runAfter(10, callMock);
+        async.runAfter(50, callMock);
+
+        // then
+        verify(mock, after(300).atLeastOnce()).oneArg('1');
+    }
+
+    @Test
+    public void should_verify_with_at_least_and_fail() {
+        // given
+        async.runAfter(10, callMock);
+        async.runAfter(50, callMock);
+        async.runAfter(600, callMock);
+
+        // then
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, after(300).atLeast(3)).oneArg('1');
+            }
+        }).isInstanceOf(AssertionError.class).hasMessageContaining("Wanted *at least* 3 times"); //TODO specific exception
+    }
+
+    @Test
+    public void should_verify_with_at_most() {
+        // given
+        async.runAfter(10, callMock);
+        async.runAfter(50, callMock);
+        async.runAfter(600, callMock);
+
+        // then
+        verify(mock, after(300).atMost(2)).oneArg('1');
+    }
+
+    @Test
+    public void should_verify_with_at_most_and_fail() {
+        // given
+        async.runAfter(10, callMock);
+        async.runAfter(50, callMock);
+        async.runAfter(600, callMock);
+
+        // then
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, after(300).atMost(1)).oneArg('1');
+            }
+        }).isInstanceOf(AssertionError.class).hasMessageContaining("Wanted at most 1 time but was 2"); //TODO specific exception
+    }
+
+    @Test
+    public void should_verify_with_never() {
+        // given
+        async.runAfter(500, callMock);
+
+        // then
+        verify(mock, after(50).never()).oneArg('1');
+    }
+
+    @Test
+    public void should_verify_with_never_and_fail() {
+        // given
+        async.runAfter(10, callMock);
+
+        // then
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, after(300).never()).oneArg('1');
+            }
+        }).isInstanceOf(MoreThanAllowedActualInvocations.class).hasMessageContaining("Wanted at most 0 times but was 1");
+    }
+
+    @Test
+    public void should_verify_with_only() {
+        // given
+        async.runAfter(10, callMock);
+        async.runAfter(600, callMock);
+
+        // then
+        verify(mock, after(300).only()).oneArg('1');
+    }
+
+    @Test
+    public void should_verify_with_only_and_fail() {
+        // given
+        async.runAfter(10, callMock);
+        async.runAfter(50, callMock);
+
+        // then
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, after(300).only()).oneArg('1');
+            }
+        }).isInstanceOf(AssertionError.class).hasMessageContaining("No interactions wanted here"); //TODO specific exception
+    }
+
+    @Test
+    public void should_fail_early_when_at_most_is_used() {
+        watch.start();
+
+        // when
+        async.runAfter(50, callMock);
+        async.runAfter(100, callMock);
+
+        // then
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            public void call() {
+                verify(mock, after(10000).atMost(1)).oneArg('1');
+            }
+        }).isInstanceOf(MoreThanAllowedActualInvocations.class);
+
+        // using generous number to avoid timing issues
+        watch.assertElapsedTimeIsLessThan(2000, MILLISECONDS);
+    }
+
+    @Test
+    public void should_fail_early_when_never_is_used() {
+        watch.start();
+
+        // when
+        async.runAfter(50, callMock);
+
+        // then
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            public void call() {
+                verify(mock, after(10000).never()).oneArg('1');
+            }
+        }).isInstanceOf(MoreThanAllowedActualInvocations.class);
+
+        // using generous number to avoid timing issues
+        watch.assertElapsedTimeIsLessThan(2000, MILLISECONDS);
+    }
+
+    @Test
+    @Ignore //TODO nice to have
+    public void should_fail_early_when_only_is_used() {
+        watch.start();
+
+        // when
+        async.runAfter(50, callMock);
+        async.runAfter(100, callMock);
+
+        // then
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            public void call() {
+                verify(mock, after(10000).only()).oneArg('1');
+            }
+        }).isInstanceOf(NoInteractionsWanted.class);
+
+        // using generous number to avoid timing issues
+        watch.assertElapsedTimeIsLessThan(2000, MILLISECONDS);
+    }
+
+    @Test
+    @Ignore //TODO nice to have
+    public void should_fail_early_when_time_x_is_used() {
+        watch.start();
+
+        // when
+        async.runAfter(50, callMock);
+        async.runAfter(100, callMock);
+
+        // then
+        assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            public void call() {
+                verify(mock, after(10000).times(1)).oneArg('1');
+            }
+        }).isInstanceOf(NoInteractionsWanted.class);
+
+        // using generous number to avoid timing issues
+        watch.assertElapsedTimeIsLessThan(2000, MILLISECONDS);
+    }
+}
diff --git a/src/test/java/org/mockitousage/verification/VerificationWithTimeoutTest.java b/src/test/java/org/mockitousage/verification/VerificationWithTimeoutTest.java
index 798e0e8..1a3b345 100644
--- a/src/test/java/org/mockitousage/verification/VerificationWithTimeoutTest.java
+++ b/src/test/java/org/mockitousage/verification/VerificationWithTimeoutTest.java
@@ -5,161 +5,198 @@
 
 package org.mockitousage.verification;
 
+import org.assertj.core.api.Assertions;
+import org.assertj.core.api.ThrowableAssert;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.mockito.InOrder;
 import org.mockito.Mock;
-import org.mockito.exceptions.base.MockitoAssertionError;
-import org.mockito.exceptions.verification.NoInteractionsWanted;
 import org.mockito.exceptions.verification.TooLittleActualInvocations;
 import org.mockito.junit.MockitoRule;
 import org.mockitousage.IMethods;
-import org.mockitoutil.RetryRule;
+import org.mockitoutil.Stopwatch;
+import org.mockitoutil.async.AsyncTesting;
 
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.junit.rules.ExpectedException.none;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.never;
+import java.util.concurrent.TimeUnit;
+
+import static org.mockito.Mockito.after;
 import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.junit.MockitoJUnit.rule;
+import static org.mockitoutil.Stopwatch.createNotStarted;
 
 public class VerificationWithTimeoutTest {
 
-    @Rule
-    public MockitoRule mockito = rule();
+    @Rule public MockitoRule mockito = rule();
 
-    @Rule
-    public RetryRule retryRule = RetryRule.attempts(4);
+    private Stopwatch watch = createNotStarted();
 
-    @Rule
-    public ExpectedException exception = none();
+    @Mock private IMethods mock;
 
-    @Mock
-    private IMethods mock;
-
-    private DelayedExecution delayedExecution;
+    private AsyncTesting async;
 
     @Before
     public void setUp() {
-        delayedExecution = new DelayedExecution();
+        async = new AsyncTesting();
     }
 
     @After
-    public void tearDown() throws InterruptedException {
-        delayedExecution.close();
+    public void tearDown() {
+        async.cleanUp();
     }
 
     @Test
-    public void shouldVerifyWithTimeout() throws Exception {
+    public void should_verify_with_timeout() {
         // when
-        delayedExecution.callAsync(30, MILLISECONDS, callMock('c'));
+        async.runAfter(50, callMock('c'));
+        async.runAfter(500, callMock('c'));
 
         // then
-        verify(mock, timeout(100)).oneArg('c');
-        verify(mock, timeout(100).atLeastOnce()).oneArg('c');
-        verify(mock, timeout(100).times(1)).oneArg('c');
-        verify(mock).oneArg('c');
-        verify(mock, times(1)).oneArg('c');
+        verify(mock, timeout(200).only()).oneArg('c');
+        verify(mock).oneArg('c'); //sanity check
     }
 
     @Test
-    public void shouldFailVerificationWithTimeout() throws Exception {
+    public void should_verify_with_timeout_and_fail() {
         // when
-        delayedExecution.callAsync(30, MILLISECONDS, callMock('c'));
+        async.runAfter(200, callMock('c'));
 
         // then
-        verify(mock, never()).oneArg('c');
-        exception.expect(MockitoAssertionError.class);
-        verify(mock, timeout(20).atLeastOnce()).oneArg('c');
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, timeout(50).only()).oneArg('c');
+            }
+        }).isInstanceOf(AssertionError.class).hasMessageContaining("Wanted but not invoked");
+        //TODO let's have a specific exception vs. generic assertion error + message
     }
 
     @Test
-    public void shouldAllowMixingOtherModesWithTimeout() throws Exception {
+    @Ignore //TODO nice to have
+    public void should_verify_with_timeout_and_fail_early() {
         // when
-        delayedExecution.callAsync(10, MILLISECONDS, callMock('c'));
-        delayedExecution.callAsync(10, MILLISECONDS, callMock('c'));
+        callMock('c');
+        callMock('c');
+
+        watch.start();
 
         // then
-        verify(mock, timeout(100).atLeast(1)).oneArg('c');
-        verify(mock, timeout(100).times(2)).oneArg('c');
-        verifyNoMoreInteractions(mock);
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, timeout(2000)).oneArg('c');
+            }
+        }).isInstanceOf(AssertionError.class).hasMessageContaining("Wanted but not invoked");
+
+        watch.assertElapsedTimeIsLessThan(1000, TimeUnit.MILLISECONDS);
     }
 
     @Test
-    public void shouldAllowMixingOtherModesWithTimeoutAndFail() throws Exception {
+    public void should_verify_with_times_x() {
         // when
-        delayedExecution.callAsync(10, MILLISECONDS, callMock('c'));
-        delayedExecution.callAsync(10, MILLISECONDS, callMock('c'));
+        async.runAfter(50, callMock('c'));
+        async.runAfter(100, callMock('c'));
+        async.runAfter(600, callMock('c'));
 
         // then
-        verify(mock, timeout(100).atLeast(1)).oneArg('c');
-        exception.expect(TooLittleActualInvocations.class);
-        verify(mock, timeout(100).times(3)).oneArg('c');
+        verify(mock, timeout(300).times(2)).oneArg('c');
     }
 
     @Test
-    public void shouldAllowMixingOnlyWithTimeout() throws Exception {
+    public void should_verify_with_times_x_and_fail() {
         // when
-        delayedExecution.callAsync(30, MILLISECONDS, callMock('c'));
+        async.runAfter(10, callMock('c'));
+        async.runAfter(200, callMock('c'));
 
         // then
-        verify(mock, never()).oneArg('c');
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, timeout(100).times(2)).oneArg('c');
+            }
+        }).isInstanceOf(TooLittleActualInvocations.class);
+    }
+
+    @Test
+    public void should_verify_with_at_least() {
+        // when
+        async.runAfter(10, callMock('c'));
+        async.runAfter(50, callMock('c'));
+
+        // then
+        verify(mock, timeout(200).atLeast(2)).oneArg('c');
+    }
+
+    @Test
+    public void should_verify_with_at_least_once() {
+        // when
+        async.runAfter(10, callMock('c'));
+        async.runAfter(50, callMock('c'));
+
+        // then
+        verify(mock, timeout(200).atLeastOnce()).oneArg('c');
+    }
+
+    @Test
+    public void should_verify_with_at_least_and_fail() {
+        // when
+        async.runAfter(10, callMock('c'));
+        async.runAfter(50, callMock('c'));
+
+        // then
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            public void call() {
+                verify(mock, timeout(100).atLeast(3)).oneArg('c');
+            }
+        }).isInstanceOf(TooLittleActualInvocations.class);
+    }
+
+    @Test
+    public void should_verify_with_only() {
+        // when
+        async.runAfter(10, callMock('c'));
+        async.runAfter(300, callMock('c'));
+
+        // then
         verify(mock, timeout(100).only()).oneArg('c');
     }
 
     @Test
-    public void shouldAllowMixingOnlyWithTimeoutAndFail() throws Exception {
+    @Ignore("not testable, probably timeout().only() does not make sense")
+    public void should_verify_with_only_and_fail() {
         // when
-        delayedExecution.callAsync(30, MILLISECONDS, callMock('c'));
-
-        // and when
-        mock.oneArg('x');
+        async.runAfter(10, callMock('c'));
+        async.runAfter(50, callMock('c'));
 
         // then
-        verify(mock, never()).oneArg('c');
-        exception.expect(NoInteractionsWanted.class);
-        verify(mock, timeout(100).only()).oneArg('c');
-    }
-
-    /**
-     * This test is JUnit-specific because the code behaves different if JUnit
-     * is used.
-     */
-    @Test
-    public void canIgnoreInvocationsWithJunit() throws InterruptedException {
-        // when
-        delayedExecution.callAsync(10, MILLISECONDS, callMock('1'));
-
-        // then
-        verify(mock, timeout(50)).oneArg('1');
-
-        // when
-        delayedExecution.callAsync(10, MILLISECONDS, callMock('2'));
-        delayedExecution.callAsync(20, MILLISECONDS, callMock('3'));
-
-        // then
-        verify(mock, timeout(50)).oneArg('3');
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, after(200).only()).oneArg('c');
+            }
+        }).isInstanceOf(AssertionError.class);
     }
 
     @Test
-    public void shouldAllowTimeoutVerificationInOrder() throws Exception {
+    @Ignore //TODO nice to have
+    public void should_verify_with_only_and_fail_early() {
         // when
-        delayedExecution.callAsync(50, MILLISECONDS, callMock('1'));
+        callMock('c');
+        callMock('c');
 
-        // and when
-        mock.oneArg('x');
+        watch.start();
 
         // then
-        InOrder inOrder = inOrder(mock);
-        inOrder.verify(mock).oneArg('x');
-        inOrder.verify(mock, never()).oneArg('1');
-        inOrder.verify(mock, timeout(100)).oneArg('1');
+        Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
+            @Override
+            public void call() {
+                verify(mock, timeout(2000).only()).oneArg('c');
+            }
+        }).isInstanceOf(AssertionError.class).hasMessageContaining("Wanted but not invoked"); //TODO specific exception
+
+        watch.assertElapsedTimeIsLessThan(1000, TimeUnit.MILLISECONDS);
     }
 
     private Runnable callMock(final char c) {
diff --git a/src/test/java/org/mockitoutil/Stopwatch.java b/src/test/java/org/mockitoutil/Stopwatch.java
index 6cde867..c2140dd 100644
--- a/src/test/java/org/mockitoutil/Stopwatch.java
+++ b/src/test/java/org/mockitoutil/Stopwatch.java
@@ -4,13 +4,14 @@
  */
 package org.mockitoutil;
 
+import org.mockito.exceptions.base.MockitoAssertionError;
+
+import java.util.concurrent.TimeUnit;
+
 import static java.lang.String.format;
 import static java.lang.System.nanoTime;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
-import java.util.concurrent.TimeUnit;
-import org.mockito.exceptions.base.MockitoAssertionError;
-
 /**
  * This class can be uses as stopwatch to assert that a given time is elapsed or not.
  */
@@ -66,4 +67,16 @@
     private static void fail(String message, long expectedNanos, long elapsedNanos) {
         throw new MockitoAssertionError(format(message, NANOSECONDS.toMillis(expectedNanos), NANOSECONDS.toMillis(elapsedNanos)));
     }
+
+    /**
+     * Waits for specific amount of millis using 'Thread.sleep()'.
+     * Rethrows InterruptedException.
+     */
+    public void waitFor(int millis) {
+        try {
+            Thread.sleep(millis);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
diff --git a/src/test/java/org/mockitoutil/TestBase.java b/src/test/java/org/mockitoutil/TestBase.java
index ca3d7b8..98066eb 100644
--- a/src/test/java/org/mockitoutil/TestBase.java
+++ b/src/test/java/org/mockitoutil/TestBase.java
@@ -5,6 +5,7 @@
 
 package org.mockitoutil;
 
+import org.assertj.core.api.Condition;
 import org.junit.After;
 import org.junit.Before;
 import org.mockito.MockitoAnnotations;
@@ -31,6 +32,18 @@
  */
 public class TestBase {
 
+    /**
+     * Condition to be used with AssertJ
+     */
+    public static Condition<Throwable> hasMessageContaining(final String substring) {
+        return new Condition<Throwable>() {
+            @Override
+            public boolean matches(Throwable e) {
+                return e.getMessage().contains(substring);
+            }
+        };
+    }
+
     @After
     public void cleanUpConfigInAnyCase() {
         ConfigurationAccess.getConfig().overrideCleansStackTrace(false);
diff --git a/src/test/java/org/mockitoutil/async/AsyncTesting.java b/src/test/java/org/mockitoutil/async/AsyncTesting.java
new file mode 100644
index 0000000..3b11e10
--- /dev/null
+++ b/src/test/java/org/mockitoutil/async/AsyncTesting.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitoutil.async;
+
+import java.util.LinkedList;
+
+/**
+ * Streamlines testing async code for Mockito tests.
+ *
+ * Instances of this class are NOT thread safe (intentionally, they are not required to be thread safe)
+ */
+public class AsyncTesting {
+
+    //Sanity limit of threas. Increase it if justified.
+    private final static int MAX_THREADS = 3;
+
+    private final LinkedList<Exception> problems = new LinkedList<Exception>();
+    private final LinkedList<Thread> threads = new LinkedList<Thread>();
+    private boolean stopping;
+
+    /**
+     * Schedules execution of runnable with some delay.
+     * Starts thread immediately and returns.
+     * The thread will execute the runnable after given delay in millis.
+     *
+     * @param delayMillis - the delay in millis
+     * @param runnable - to be executed in a thread after delay
+     */
+    public void runAfter(final int delayMillis, final Runnable runnable) {
+        if (threads.size() == MAX_THREADS) {
+            throw new RuntimeException("Please don't schedule any more threads. Figure out how to test the code with minimum amount of threads");
+        }
+        Thread t = new Thread() {
+            public void run() {
+                try {
+                    Thread.sleep(delayMillis);
+                    runnable.run();
+                } catch (Exception e) {
+                    boolean cleanStop = e instanceof InterruptedException && stopping;
+                    if (!cleanStop) {
+                        problems.add(e);
+                    }
+                }
+            }
+        };
+        System.out.println("[AsyncTesting] Starting thread that will execute the runnable after " + delayMillis + " millis. Threads so far: " + threads.size());
+        threads.add(t);
+        t.start();
+    }
+
+    /**
+     * Interrupts and waits for all threads to complete (using 'join()').
+     * Rethrows exceptions accumulated by the execution of threads.
+     */
+    public void cleanUp() {
+        stopping = true;
+        System.out.println("[AsyncTesting] Interrupting and waiting for " + threads.size() + " threads to complete...");
+        while(!threads.isEmpty()) {
+            Thread t = threads.removeFirst();
+            try {
+                t.interrupt();
+                t.join();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        if (!problems.isEmpty()) {
+            throw new RuntimeException("Caught " + problems.size() + " exception(s). First one is included as cause", problems.getFirst());
+        }
+    }
+}
diff --git a/src/test/java/org/mockitoutil/async/AsyncTestingTest.java b/src/test/java/org/mockitoutil/async/AsyncTestingTest.java
new file mode 100644
index 0000000..4aacfe5
--- /dev/null
+++ b/src/test/java/org/mockitoutil/async/AsyncTestingTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+package org.mockitoutil.async;
+
+import org.junit.After;
+import org.junit.Test;
+import org.mockitoutil.Stopwatch;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.junit.Assert.assertEquals;
+import static org.mockitoutil.Stopwatch.createNotStarted;
+
+public class AsyncTestingTest {
+
+    private AsyncTesting async = new AsyncTesting();
+    private Stopwatch watch = createNotStarted();
+
+    @After
+    public void after() {
+        async.cleanUp();
+    }
+
+    @Test
+    public void sanity_test() {
+        //given
+        watch.start();
+        final AtomicInteger value = new AtomicInteger(0);
+
+        //when
+        async.runAfter(200, new Runnable() {
+            public void run() {
+                value.incrementAndGet();
+            }
+        });
+
+        //then the runnable is truly async and has not ran yet:
+        assertEquals(0, value.get());
+
+        //after some wait...
+        watch.waitFor(300);
+
+        //we actually waited for some time
+        watch.assertElapsedTimeIsMoreThan(200, MILLISECONDS);
+
+        //and the async has actually ran:
+        assertEquals(1, value.get());
+    }
+}
diff --git a/subprojects/android/src/main/java/org/mockito/android/internal/creation/AndroidLoadingStrategy.java b/subprojects/android/src/main/java/org/mockito/android/internal/creation/AndroidLoadingStrategy.java
index 600b9bc..5a66ab1 100644
--- a/subprojects/android/src/main/java/org/mockito/android/internal/creation/AndroidLoadingStrategy.java
+++ b/subprojects/android/src/main/java/org/mockito/android/internal/creation/AndroidLoadingStrategy.java
@@ -4,18 +4,19 @@
  */
 package org.mockito.android.internal.creation;
 
-import static org.mockito.internal.util.StringUtil.join;
-
-import java.io.File;
 import net.bytebuddy.android.AndroidClassLoadingStrategy;
 import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
 import org.mockito.exceptions.base.MockitoException;
 import org.mockito.internal.creation.bytebuddy.SubclassLoader;
 
+import java.io.File;
+
+import static org.mockito.internal.util.StringUtil.join;
+
 class AndroidLoadingStrategy implements SubclassLoader {
 
     @Override
-    public ClassLoadingStrategy<ClassLoader> getStrategy(Class<?> mockFeatures) {
+    public ClassLoadingStrategy<ClassLoader> resolveStrategy(Class<?> mockedType, ClassLoader classLoader, boolean codegen) {
         File target = AndroidTempFileLocator.target;
         if (target == null) {
             throw new MockitoException(join(
diff --git a/subprojects/inline/src/test/java/org/mockitoinline/FinalClassMockingTest.java b/subprojects/inline/src/test/java/org/mockitoinline/FinalClassMockingTest.java
index 0f2ea78..80c9de8 100644
--- a/subprojects/inline/src/test/java/org/mockitoinline/FinalClassMockingTest.java
+++ b/subprojects/inline/src/test/java/org/mockitoinline/FinalClassMockingTest.java
@@ -9,6 +9,7 @@
 
 public class FinalClassMockingTest {
 
+    @SuppressWarnings("CheckReturnValue")
     @Test
     public void no_exception_while_mocking_final_class() throws Exception {
         Mockito.mock(FinalClass.class);