Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mockito #1013: Defines and implements API for static mocking. #1955

Merged
merged 2 commits into from Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/main/java/org/mockito/Captor.java
Expand Up @@ -15,9 +15,16 @@
*
* @Captor ArgumentCaptor<AsyncCallback<Foo>> captor;
*
* private AutoCloseable closeable;
*
* @Before
* public void init(){
* MockitoAnnotations.initMocks(this);
* public void open() {
* closeable = MockitoAnnotations.openMocks(this);
* }
*
* @After
* public void release() throws Exception {
* closeable.close();
* }
*
* @Test public void shouldDoSomethingUseful() {
Expand Down
22 changes: 14 additions & 8 deletions src/main/java/org/mockito/InjectMocks.java
Expand Up @@ -71,8 +71,14 @@
*
* public class SampleBaseTestCase {
*
* @Before public void initMocks() {
* MockitoAnnotations.initMocks(this);
* private AutoCloseable closeable;
*
* @Before public void openMocks() {
* closeable = MockitoAnnotations.openMocks(this);
* }
*
* @After public void releaseMocks() throws Exception {
* closeable.close();
* }
* }
* </code></pre>
Expand Down Expand Up @@ -141,11 +147,11 @@
* </p>
*
* <p>
* <strong><code>MockitoAnnotations.initMocks(this)</code></strong> method has to be called to initialize annotated objects.
* In above example, <code>initMocks()</code> is called in &#064;Before (JUnit4) method of test's base class.
* For JUnit3 <code>initMocks()</code> can go to <code>setup()</code> method of a base class.
* <strong>Instead</strong> you can also put initMocks() in your JUnit runner (&#064;RunWith) or use the built-in
* {@link MockitoJUnitRunner}.
* <strong><code>MockitoAnnotations.openMocks(this)</code></strong> method has to be called to initialize annotated objects.
* In above example, <code>openMocks()</code> is called in &#064;Before (JUnit4) method of test's base class.
* For JUnit3 <code>openMocks()</code> can go to <code>setup()</code> method of a base class.
* <strong>Instead</strong> you can also put openMocks() in your JUnit runner (&#064;RunWith) or use the built-in
* {@link MockitoJUnitRunner}. Also, make sure to release any mocks after disposing your test class with a corresponding hook.
* </p>
*
* <p>
Expand All @@ -155,7 +161,7 @@
*
* @see Mock
* @see Spy
* @see MockitoAnnotations#initMocks(Object)
* @see MockitoAnnotations#openMocks(Object)
* @see MockitoJUnitRunner
* @since 1.8.3
*/
Expand Down
23 changes: 15 additions & 8 deletions src/main/java/org/mockito/Mock.java
Expand Up @@ -23,6 +23,7 @@
* <li>Minimizes repetitive mock creation code.</li>
* <li>Makes the test class more readable.</li>
* <li>Makes the verification error easier to read because the <b>field name</b> is used to identify the mock.</li>
* <li>Automatically detects static mocks of type {@link MockedStatic} and infers the static mock type of the type parameter.</li>
* </ul>
*
* <pre class="code"><code class="java">
Expand All @@ -43,24 +44,30 @@
*
* public class SampleBaseTestCase {
*
* &#064;Before public void initMocks() {
* MockitoAnnotations.initMocks(this);
* private AutoCloseable closeable;
*
* &#064;Before public void openMocks() {
* closeable = MockitoAnnotations.openMocks(this);
* }
*
* &#064;After public void releaseMocks() throws Exception {
* closeable.close();
* }
* }
* </code></pre>
*
* <p>
* <strong><code>MockitoAnnotations.initMocks(this)</code></strong> method has to be called to initialize annotated objects.
* In above example, <code>initMocks()</code> is called in &#064;Before (JUnit4) method of test's base class.
* For JUnit3 <code>initMocks()</code> can go to <code>setup()</code> method of a base class.
* <strong>Instead</strong> you can also put initMocks() in your JUnit runner (&#064;RunWith) or use the built-in
* {@link MockitoJUnitRunner}.
* <strong><code>MockitoAnnotations.openMocks(this)</code></strong> method has to be called to initialize annotated objects.
* In above example, <code>openMocks()</code> is called in &#064;Before (JUnit4) method of test's base class.
* For JUnit3 <code>openMocks()</code> can go to <code>setup()</code> method of a base class.
* <strong>Instead</strong> you can also put openMocks() in your JUnit runner (&#064;RunWith) or use the built-in
* {@link MockitoJUnitRunner}. Also, make sure to release any mocks after disposing your test class with a corresponding hook.
* </p>
*
* @see Mockito#mock(Class)
* @see Spy
* @see InjectMocks
* @see MockitoAnnotations#initMocks(Object)
* @see MockitoAnnotations#openMocks(Object)
* @see MockitoJUnitRunner
*/
@Target({FIELD, PARAMETER})
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/org/mockito/MockSettings.java
Expand Up @@ -340,6 +340,21 @@ public interface MockSettings extends Serializable {
@Incubating
<T> MockCreationSettings<T> build(Class<T> typeToMock);

/**
* Creates immutable view of mock settings used later by Mockito, for use within a static mocking.
* Framework integrators can use this method to create instances of creation settings
* and use them in advanced use cases, for example to create invocations with {@link InvocationFactory},
* or to implement custom {@link MockHandler}.
* Since {@link MockCreationSettings} is {@link NotExtensible}, Mockito public API needs a creation method for this type.
*
* @param classToMock class to mock
* @param <T> type to mock
* @return immutable view of mock settings
* @since 2.10.0
*/
@Incubating
<T> MockCreationSettings<T> buildStatic(Class<T> classToMock);

/**
* 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
Expand Down
78 changes: 78 additions & 0 deletions src/main/java/org/mockito/MockedStatic.java
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito;

import org.mockito.stubbing.OngoingStubbing;
import org.mockito.verification.VerificationMode;

import static org.mockito.Mockito.*;

/**
* Represents an active mock of a type's static methods. The mocking only affects the thread
* on which this static mock was created and it is not safe to use this object from another
* thread. The static mock is released when this object's {@link MockedStatic#close()} method
* is invoked. If this object is never closed, the static mock will remain active on the
* initiating thread. It is therefore recommended to create this object within a try-with-resources
* statement unless when managed explicitly, for example by using a JUnit rule or extension.
* <p>
* If the {@link Mock} annotation is used on fields or method parameters of this type, a static mock
* is created instead of a regular mock. The static mock is activated and released upon completing any
* relevant test.
*
* @param <T> The type being mocked.
*/
@Incubating
public interface MockedStatic<T> extends AutoCloseable {

/**
* See {@link Mockito#when(Object)}.
*/
<S> OngoingStubbing<S> when(Verification verification);

/**
* See {@link Mockito#verify(Object)}.
*/
default void verify(Verification verification) {
verify(times(1), verification);
}

/**
* See {@link Mockito#verify(Object, VerificationMode)}.
*/
void verify(VerificationMode mode, Verification verification);

/**
* See {@link Mockito#reset(Object[])}.
*/
void reset();

/**
* See {@link Mockito#clearInvocations(Object[])}.
*/
void clearInvocations();

/**
* {@link Mockito#verifyNoMoreInteractions(Object...)}.
*/
void verifyNoMoreInteractions();

/**
* See {@link Mockito#verifyNoInteractions(Object...)}.
*/
void verifyNoInteractions();

@Override
void close();

/**
* Releases this static mock and is non-operational if already released.
*/
void closeOnDemand();

interface Verification {

void apply() throws Throwable;
}
}
99 changes: 95 additions & 4 deletions src/main/java/org/mockito/Mockito.java
Expand Up @@ -105,6 +105,7 @@
* <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="#47">47. New API for clearing mock state in inline mocking (Since 2.25.0)</a><br/>
* <a href="#48">48. New API for mocking static methods (Since 3.4.0)</a><br/>
* </b>
*
* <h3 id="0">0. <a class="meaningful_link" href="#mockito2" name="mockito2">Migrating to Mockito 2</a></h3>
Expand Down Expand Up @@ -461,7 +462,7 @@
* runner:
*
* <pre class="code"><code class="java">
* MockitoAnnotations.initMocks(testClass);
* MockitoAnnotations.openMocks(testClass);
* </code></pre>
*
* You can use built-in runner: {@link MockitoJUnitRunner} or a rule: {@link MockitoRule}.
Expand Down Expand Up @@ -863,7 +864,7 @@
* should only use partial mocks as a last resort. See point 16 about partial mocks.
*
* <p>
* All new annotations are <b>*only*</b> processed on {@link MockitoAnnotations#initMocks(Object)}.
* All new annotations are <b>*only*</b> processed on {@link MockitoAnnotations#openMocks(Object)}.
* Just like for &#064;{@link Mock} annotation you can use the built-in runner: {@link MockitoJUnitRunner} or rule:
* {@link MockitoRule}.
* <p>
Expand Down Expand Up @@ -907,7 +908,7 @@
* Mockito will now try to instantiate &#064;{@link Spy} and will instantiate &#064;{@link InjectMocks} fields
* using <b>constructor</b> injection, <b>setter</b> injection, or <b>field</b> injection.
* <p>
* To take advantage of this feature you need to use {@link MockitoAnnotations#initMocks(Object)}, {@link MockitoJUnitRunner}
* To take advantage of this feature you need to use {@link MockitoAnnotations#openMocks(Object)}, {@link MockitoJUnitRunner}
* or {@link MockitoRule}.
* <p>
* Read more about available tricks and the rules of injection in the javadoc for {@link InjectMocks}
Expand Down Expand Up @@ -1144,7 +1145,7 @@
*
* <ul>
* <li>Annotating the JUnit test class with a <code>&#064;{@link org.junit.runner.RunWith}({@link MockitoJUnitRunner}.class)</code></li>
* <li>Invoking <code>{@link MockitoAnnotations#initMocks(Object)}</code> in the <code>&#064;{@link org.junit.Before}</code> method</li>
* <li>Invoking <code>{@link MockitoAnnotations#openMocks(Object)}</code> in the <code>&#064;{@link org.junit.Before}</code> method</li>
* </ul>
*
* Now you can choose to use a rule :
Expand Down Expand Up @@ -1541,6 +1542,29 @@
* 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.
*
*
* <h3 id="48">48. <a class="meaningful_link" href="#static_mocks" name="static_mocks">Mocking static methods</a> (since 3.4.0)</h3>
*
* When using the <a href="#0.2">inline mock maker</a>, it is possible to mock static method invocations within the current
* thread and a user-defined scope. This way, Mockito assures that concurrently and sequentially running tests do not interfere.
*
* To make sure a static mock remains temporary, it is recommended to define the scope within a try-with-resources construct.
* In the following example, the <code>Foo</code> type's static method would return <code>foo</code> unless mocked:
*
* <pre class="code"><code class="java">
* assertEquals("foo", Foo.method());
* try (MockedStatic<Foo> mocked = mockStatic(Foo.class)) {
* mocked.when(Foo::method).thenReturn("bar");
* assertEquals("bar", Foo.method());
* mocked.verify(Foo::method);
raphw marked this conversation as resolved.
Show resolved Hide resolved
* }
* assertEquals("foo", Foo.method());
* </code></pre>
*
* Due to the defined scope of the static mock, it returns to its original behvior once the scope is released. To define mock
* behavior and to verify static method invocations, use the <code>MockedStatic</code> that is returned.
* <p>
*/
@SuppressWarnings("unchecked")
public class Mockito extends ArgumentMatchers {
Expand Down Expand Up @@ -2026,6 +2050,73 @@ public static <T> T spy(Class<T> classToSpy) {
classToSpy, withSettings().useConstructor().defaultAnswer(CALLS_REAL_METHODS));
}

/**
* Creates a thread-local mock controller for all static methods of the given class or interface.
* The returned object's {@link MockedStatic#close()} method must be called upon completing the
* test or the mock will remain active on the current thread.
* <p>
* See examples in javadoc for {@link Mockito} class
*
* @param classToMock class or interface of which static mocks should be mocked.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock) {
return mockStatic(classToMock, withSettings());
}

/**
* Creates a thread-local mock controller for all static methods of the given class or interface.
* The returned object's {@link MockedStatic#close()} method must be called upon completing the
* test or the mock will remain active on the current thread.
* <p>
* See examples in javadoc for {@link Mockito} class
*
* @param classToMock class or interface of which static mocks should be mocked.
* @param defaultAnswer the default answer when invoking static methods.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock, Answer defaultAnswer) {
return mockStatic(classToMock, withSettings().defaultAnswer(defaultAnswer));
}

/**
* Creates a thread-local mock controller for all static methods of the given class or interface.
* The returned object's {@link MockedStatic#close()} method must be called upon completing the
* test or the mock will remain active on the current thread.
* <p>
* See examples in javadoc for {@link Mockito} class
*
* @param classToMock class or interface of which static mocks should be mocked.
* @param name the name of the mock to use in error messages.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock, String name) {
return mockStatic(classToMock, withSettings().name(name));
}

/**
* Creates a thread-local mock controller for all static methods of the given class or interface.
* The returned object's {@link MockedStatic#close()} method must be called upon completing the
* test or the mock will remain active on the current thread.
* <p>
* See examples in javadoc for {@link Mockito} class
*
* @param classToMock class or interface of which static mocks should be mocked.
* @param mockSettings the settings to use where only name and default answer are considered.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock, MockSettings mockSettings) {
return MOCKITO_CORE.mockStatic(classToMock, mockSettings);
}

/**
* Enables stubbing methods. Use it when you want the mock to return particular value when particular method is called.
* <p>
Expand Down