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

Pre release 3.5.0 #2004

Merged
merged 8 commits into from Aug 15, 2020
40 changes: 40 additions & 0 deletions src/main/java/org/mockito/MockedConstruction.java
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito;

import java.lang.reflect.Constructor;
import java.util.List;

/**
* Represents a mock of any object construction of the represented type. Within the scope of the
* mocked construction, the invocation of any interceptor will generate a mock which will be
* prepared as specified when generating this scope. The mock can also be received via this
* instance.
* <p>
* If the {@link Mock} annotation is used on fields or method parameters of this type, a mocked
* construction is created instead of a regular mock. The mocked construction is activated and
* released upon completing any relevant test.
*
* @param <T> The type for which the construction is being mocked.
*/
@Incubating
public interface MockedConstruction<T> extends ScopedMock {

List<T> constructed();

interface Context {

int getCount();

Constructor<?> constructor();

List<?> arguments();
}

interface MockInitializer<T> {

void prepare(T mock, Context context) throws Throwable;
}
}
20 changes: 1 addition & 19 deletions src/main/java/org/mockito/MockedStatic.java
Expand Up @@ -24,7 +24,7 @@
* @param <T> The type being mocked.
*/
@Incubating
public interface MockedStatic<T> extends AutoCloseable {
public interface MockedStatic<T> extends ScopedMock {

/**
* See {@link Mockito#when(Object)}.
Expand Down Expand Up @@ -63,24 +63,6 @@ default void verify(Verification verification) {
*/
void verifyNoInteractions();

/**
* Checks if this mock is closed.
*
* @return {@code true} if this mock is closed.
*/
boolean isClosed();

/**
* Releases this static mock and throws a {@link org.mockito.exceptions.base.MockitoException} if closed already.
*/
@Override
void close();

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

interface Verification {

void apply() throws Throwable;
Expand Down
188 changes: 175 additions & 13 deletions src/main/java/org/mockito/Mockito.java
Expand Up @@ -28,18 +28,10 @@
import org.mockito.quality.Strictness;
import org.mockito.session.MockitoSessionBuilder;
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;
import org.mockito.stubbing.VoidAnswer1;
import org.mockito.verification.After;
import org.mockito.verification.Timeout;
import org.mockito.verification.VerificationAfterDelay;
import org.mockito.verification.VerificationMode;
import org.mockito.verification.VerificationWithTimeout;
import org.mockito.stubbing.*;
import org.mockito.verification.*;

import java.util.function.Function;

/**
* <p align="left"><img src="logo.png" srcset="logo@2x.png 2x" alt="Mockito logo"/></p>
Expand Down Expand Up @@ -106,6 +98,7 @@
* <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/>
* <a href="#49">49. New API for mocking object construction (Since 3.5.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 @@ -1565,9 +1558,32 @@
* 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
* Due to the defined scope of the static mock, it returns to its original behavior once the scope is released. To define mock
* behavior and to verify static method invocations, use the <code>MockedStatic</code> that is returned.
* <p>
*
* <h3 id="49">49. <a class="meaningful_link" href="#mocked_construction" name="mocked_construction">Mocking object construction</a> (since 3.5.0)</h3>
*
* When using the <a href="#0.2">inline mock maker</a>, it is possible to generate mocks on constructor 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 constructor mocks remain temporary, it is recommended to define the scope within a try-with-resources construct.
* In the following example, the <code>Foo</code> type's construction would generate a mock:
*
* <pre class="code"><code class="java">
* assertEquals("foo", Foo.method());
* try (MockedConstruction<Foo> mocked = mockConstruction(Foo.class)) {
* Foo foo = new Foo();
* when(foo.method()).thenReturn("bar");
* assertEquals("bar", foo.method());
* verify(foo).method();
* }
* assertEquals("foo", foo.method());
* </code></pre>
*
* Due to the defined scope of the mocked construction, object construction returns to its original behavior once the scope is
* released. To define mock behavior and to verify static method invocations, use the <code>MockedConstruction</code> that is returned.
* <p>
*/
@SuppressWarnings("unchecked")
public class Mockito extends ArgumentMatchers {
Expand Down Expand Up @@ -2144,6 +2160,152 @@ public static <T> MockedStatic<T> mockStatic(Class<T> classToMock, MockSettings
return MOCKITO_CORE.mockStatic(classToMock, mockSettings);
}

/**
* Creates a thread-local mock controller for all constructions of the given class.
* The returned object's {@link MockedConstruction#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 non-abstract class of which constructions should be mocked.
* @param defaultAnswer the default answer for the first created mock.
* @param additionalAnswers the default answer for all additional mocks. For any access mocks, the
* last answer is used. If this array is empty, the {@code defaultAnswer} is used.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedConstruction<T> mockConstructionWithAnswer(
Class<T> classToMock, Answer defaultAnswer, Answer... additionalAnswers) {
return mockConstruction(
classToMock,
context -> {
if (context.getCount() == 1 || additionalAnswers.length == 0) {
return withSettings().defaultAnswer(defaultAnswer);
} else if (context.getCount() >= additionalAnswers.length) {
return withSettings()
.defaultAnswer(additionalAnswers[additionalAnswers.length - 1]);
} else {
return withSettings()
.defaultAnswer(additionalAnswers[context.getCount() - 2]);
}
},
(mock, context) -> {});
}

/**
* Creates a thread-local mock controller for all constructions of the given class.
* The returned object's {@link MockedConstruction#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 non-abstract class of which constructions should be mocked.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedConstruction<T> mockConstruction(Class<T> classToMock) {
return mockConstruction(classToMock, index -> withSettings(), (mock, context) -> {});
}

/**
* Creates a thread-local mock controller for all constructions of the given class.
* The returned object's {@link MockedConstruction#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 non-abstract class of which constructions should be mocked.
* @param mockInitializer a callback to prepare a mock's methods after its instantiation.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedConstruction<T> mockConstruction(
Class<T> classToMock, MockedConstruction.MockInitializer<T> mockInitializer) {
return mockConstruction(classToMock, withSettings(), mockInitializer);
}

/**
* Creates a thread-local mock controller for all constructions of the given class.
* The returned object's {@link MockedConstruction#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 non-abstract class of which constructions should be mocked.
* @param mockSettings the mock settings to use.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedConstruction<T> mockConstruction(
Class<T> classToMock, MockSettings mockSettings) {
return mockConstruction(classToMock, context -> mockSettings);
}

/**
* Creates a thread-local mock controller for all constructions of the given class.
* The returned object's {@link MockedConstruction#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 non-abstract class of which constructions should be mocked.
* @param mockSettingsFactory the mock settings to use.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedConstruction<T> mockConstruction(
Class<T> classToMock,
Function<MockedConstruction.Context, MockSettings> mockSettingsFactory) {
return mockConstruction(classToMock, mockSettingsFactory, (mock, context) -> {});
}

/**
* Creates a thread-local mock controller for all constructions of the given class.
* The returned object's {@link MockedConstruction#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 non-abstract class of which constructions should be mocked.
* @param mockSettings the settings to use.
* @param mockInitializer a callback to prepare a mock's methods after its instantiation.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedConstruction<T> mockConstruction(
Class<T> classToMock,
MockSettings mockSettings,
MockedConstruction.MockInitializer<T> mockInitializer) {
return mockConstruction(classToMock, index -> mockSettings, mockInitializer);
}

/**
* Creates a thread-local mock controller for all constructions of the given class.
* The returned object's {@link MockedConstruction#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 non-abstract class of which constructions should be mocked.
* @param mockSettingsFactory a function to create settings to use.
* @param mockInitializer a callback to prepare a mock's methods after its instantiation.
* @return mock controller
*/
@Incubating
@CheckReturnValue
public static <T> MockedConstruction<T> mockConstruction(
Class<T> classToMock,
Function<MockedConstruction.Context, MockSettings> mockSettingsFactory,
MockedConstruction.MockInitializer<T> mockInitializer) {
return MOCKITO_CORE.mockConstruction(classToMock, mockSettingsFactory, mockInitializer);
}

/**
* Enables stubbing methods. Use it when you want the mock to return particular value when particular method is called.
* <p>
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/org/mockito/ScopedMock.java
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito;

/**
* Represents a mock with a thread-local explicit scope. Scoped mocks must be closed by the entity
* that activates the scoped mock.
*/
@Incubating
public interface ScopedMock extends AutoCloseable {

/**
* Checks if this mock is closed.
*
* @return {@code true} if this mock is closed.
*/
boolean isClosed();

/**
* Closes this scoped mock and throws an exception if already closed.
*/
@Override
void close();

/**
* Releases this scoped mock and is non-operational if already released.
*/
void closeOnDemand();
}
Expand Up @@ -13,6 +13,13 @@
*/
public class InstantiationException extends MockitoException {

/**
* @since 3.5.0
*/
public InstantiationException(String message) {
super(message);
}

/**
* @since 2.15.4
*/
Expand Down