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">
+ * @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 {
+ *
+ * @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(STRICT_STUBS);
+ *
+ * @Mock Foo foo;
+ * @Mock Bar bar;
+ *
+ * @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());
+ * }
+ *
+ * @Test public void test1() {
+ * foo.foo();
+ * }
+ *
+ * @Test public void test2() {
+ * foo.foo();
+ * }
+ *
+ * @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 {
- * @Rule
- * public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
- *
- * @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);