Skip to content

Commit

Permalink
Mockito \#1013: Defines and implements API for static mocking.
Browse files Browse the repository at this point in the history
  • Loading branch information
raphw committed Jul 2, 2020
1 parent 4fd405d commit 7ee6a25
Show file tree
Hide file tree
Showing 67 changed files with 1,348 additions and 198 deletions.
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() {
* 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
79 changes: 79 additions & 0 deletions src/main/java/org/mockito/MockedStatic.java
@@ -0,0 +1,79 @@
/*
* 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();

@FunctionalInterface
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);
* }
* 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

0 comments on commit 7ee6a25

Please sign in to comment.