summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/org/mockito/Mockito.java12
-rw-r--r--src/main/java/org/mockito/MockitoFramework.java51
-rw-r--r--src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java13
-rw-r--r--src/main/java/org/mockito/internal/framework/DefaultMockitoFramework.java23
-rw-r--r--src/main/java/org/mockito/plugins/InlineMockMaker.java52
5 files changed, 149 insertions, 2 deletions
diff --git a/src/main/java/org/mockito/Mockito.java b/src/main/java/org/mockito/Mockito.java
index 2d06e58..4058340 100644
--- a/src/main/java/org/mockito/Mockito.java
+++ b/src/main/java/org/mockito/Mockito.java
@@ -103,7 +103,8 @@ import org.mockito.verification.VerificationWithTimeout;
* <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/>
+ * <a href="#46">46. New <code>Mockito.lenient()</code> and <code>MockSettings.lenient()</code> methods (Since 2.20.0)</a><br/>
+ * <a href="#47">47. New API for clearing mock state in inline mocking (Since 2.25.0)</a><br/>
* </b>
*
* <h3 id="0">0. <a class="meaningful_link" href="#mockito2" name="mockito2">Migrating to Mockito 2</a></h3>
@@ -1532,6 +1533,15 @@ import org.mockito.verification.VerificationWithTimeout;
*
* 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!
+ *
+ * <h3 id="47">47. <a class="meaningful_link" href="#clear_inline_mocks" name="clear_inline_mocks">New API for clearing mock state in inline mocking (Since 2.25.0)</a></h3>
+ *
+ * In certain specific, rare scenarios (issue <a href="https://github.com/mockito/mockito/pull/1619">#1619</a>)
+ * inline mocking causes memory leaks.
+ * There is no clean way to mitigate this problem completely.
+ * Hence, we introduced a new API to explicitly clear mock state (only make sense in inline mocking!).
+ * See example usage in {@link MockitoFramework#clearInlineMocks()}.
+ * If you have feedback or a better idea how to solve the problem please reach out.
*/
@SuppressWarnings("unchecked")
public class Mockito extends ArgumentMatchers {
diff --git a/src/main/java/org/mockito/MockitoFramework.java b/src/main/java/org/mockito/MockitoFramework.java
index 5ffe272..58cd4b6 100644
--- a/src/main/java/org/mockito/MockitoFramework.java
+++ b/src/main/java/org/mockito/MockitoFramework.java
@@ -92,4 +92,55 @@ public interface MockitoFramework {
*/
@Incubating
InvocationFactory getInvocationFactory();
+
+ /**
+ * Clears up internal state of all inline mocks.
+ * This method is only meaningful if inline mock maker is in use.
+ * Otherwise this method is a no-op and need not be used.
+ * <p>
+ * This method is useful to tackle subtle memory leaks that are possible due to the nature of inline mocking
+ * (issue <a href="https://github.com/mockito/mockito/pull/1619">#1619</a>).
+ * If you are facing those problems, call this method at the end of the test (or in "@After" method).
+ * See examples of using "clearInlineMocks" in Mockito test code.
+ * To find out why inline mock maker keeps track of the mock objects see {@link org.mockito.plugins.InlineMockMaker}.
+ * <p>
+ * Mockito's "inline mocking" enables mocking final types, enums and final methods
+ * (read more in section 39 of {@link Mockito} javadoc).
+ * This method is only meaningful when {@link org.mockito.plugins.InlineMockMaker} is in use.
+ * If you're using a different {@link org.mockito.plugins.MockMaker} then this method is a no-op.
+ *
+ * <pre class="code"><code class="java">
+ * public class ExampleTest {
+ *
+ * &#064;After
+ * public void clearMocks() {
+ * Mockito.framework().clearInlineMocks();
+ * }
+ *
+ * &#064;Test
+ * public void someTest() {
+ * ...
+ * }
+ * }
+ * </pre>
+ *
+ * If you have feedback or a better idea how to solve the problem please reach out.
+ *
+ * @since 2.25.0
+ * @see #clearInlineMock(Object)
+ */
+ @Incubating
+ void clearInlineMocks();
+
+ /**
+ * Clears up internal state of specific inline mock.
+ * This method is a single-mock variant of {@link #clearInlineMocks()}.
+ * Please read javadoc for {@link #clearInlineMocks()}.
+ *
+ * @param mock to clear up
+ * @since 2.25.0
+ * @see #clearInlineMocks()
+ */
+ @Incubating
+ void clearInlineMock(Object mock);
}
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java
index 42f10ce..dfe2061 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InlineByteBuddyMockMaker.java
@@ -14,6 +14,7 @@ import org.mockito.internal.util.Platform;
import org.mockito.internal.util.concurrent.WeakConcurrentMap;
import org.mockito.invocation.MockHandler;
import org.mockito.mock.MockCreationSettings;
+import org.mockito.plugins.InlineMockMaker;
import java.io.File;
import java.io.FileOutputStream;
@@ -87,7 +88,7 @@ import static org.mockito.internal.util.StringUtil.join;
* support this feature.
*/
@Incubating
-public class InlineByteBuddyMockMaker implements ClassCreatingMockMaker {
+public class InlineByteBuddyMockMaker implements ClassCreatingMockMaker, InlineMockMaker {
private static final Instrumentation INSTRUMENTATION;
@@ -276,6 +277,16 @@ public class InlineByteBuddyMockMaker implements ClassCreatingMockMaker {
}
@Override
+ public void clearMock(Object mock) {
+ mocks.remove(mock);
+ }
+
+ @Override
+ public void clearAllMocks() {
+ mocks.clear();
+ }
+
+ @Override
public TypeMockability isTypeMockable(final Class<?> type) {
return new TypeMockability() {
@Override
diff --git a/src/main/java/org/mockito/internal/framework/DefaultMockitoFramework.java b/src/main/java/org/mockito/internal/framework/DefaultMockitoFramework.java
index 69a733c..d92fc28 100644
--- a/src/main/java/org/mockito/internal/framework/DefaultMockitoFramework.java
+++ b/src/main/java/org/mockito/internal/framework/DefaultMockitoFramework.java
@@ -10,6 +10,8 @@ import org.mockito.internal.invocation.DefaultInvocationFactory;
import org.mockito.internal.util.Checks;
import org.mockito.invocation.InvocationFactory;
import org.mockito.listeners.MockitoListener;
+import org.mockito.plugins.InlineMockMaker;
+import org.mockito.plugins.MockMaker;
import org.mockito.plugins.MockitoPlugins;
import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
@@ -37,4 +39,25 @@ public class DefaultMockitoFramework implements MockitoFramework {
public InvocationFactory getInvocationFactory() {
return new DefaultInvocationFactory();
}
+
+ private InlineMockMaker getInlineMockMaker() {
+ MockMaker mockMaker = Plugins.getMockMaker();
+ return (mockMaker instanceof InlineMockMaker) ? (InlineMockMaker) mockMaker : null;
+ }
+
+ @Override
+ public void clearInlineMocks() {
+ InlineMockMaker mockMaker = getInlineMockMaker();
+ if (mockMaker != null) {
+ mockMaker.clearAllMocks();
+ }
+ }
+
+ @Override
+ public void clearInlineMock(Object mock) {
+ InlineMockMaker mockMaker = getInlineMockMaker();
+ if (mockMaker != null) {
+ mockMaker.clearMock(mock);
+ }
+ }
}
diff --git a/src/main/java/org/mockito/plugins/InlineMockMaker.java b/src/main/java/org/mockito/plugins/InlineMockMaker.java
new file mode 100644
index 0000000..8771aa7
--- /dev/null
+++ b/src/main/java/org/mockito/plugins/InlineMockMaker.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 Mockito contributors
+ * This program is made available under the terms of the MIT License.
+ */
+
+package org.mockito.plugins;
+
+import org.mockito.Incubating;
+import org.mockito.MockitoFramework;
+
+/**
+ * Extension to {@link MockMaker} for mock makers that changes inline method implementations
+ * and need keep track of created mock objects.
+ * <p>
+ * Mockito's default inline mock maker keeps track of created mock objects via weak reference map.
+ * This poses a risk of memory leaks in certain scenarios
+ * (issue <a href="https://github.com/mockito/mockito/pull/1619">#1619</a>).
+ * There is no clean way to tackle those problems at the moment.
+ * Hence, {@code InlineMockMaker} interface exposes methods to explicitly clear mock references.
+ * Those methods are called by {@link MockitoFramework#clearInlineMocks()}.
+ * When the user encounters a leak, he can mitigate the problem with {@link MockitoFramework#clearInlineMocks()}.
+ * <p>
+ * {@code InlineMockMaker} is for expert users and framework integrators, when custom inline mock maker is in use.
+ * If you have a custom {@link MockMaker} that keeps track of mock objects,
+ * please have your mock maker implement {@code InlineMockMaker} interface.
+ * This way, it can participate in {@link MockitoFramework#clearInlineMocks()} API.
+ *
+ * @since 2.25.0
+ */
+@Incubating
+public interface InlineMockMaker extends MockMaker {
+
+ /**
+ * Clean up internal state for specified {@code mock}. You may assume there won't be any interaction to the specific
+ * mock after this is called.
+ *
+ * @param mock the mock instance whose internal state is to be cleaned.
+ * @since 2.25.0
+ */
+ @Incubating
+ void clearMock(Object mock);
+
+ /**
+ * Cleans up internal state for all existing mocks. You may assume there won't be any interaction to mocks created
+ * previously after this is called.
+ *
+ * @since 2.25.0
+ */
+ @Incubating
+ void clearAllMocks();
+
+}