Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 59 additions & 1 deletion src/main/java/org/mockito/Mockito.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@
import org.mockito.stubbing.OngoingStubbing;
import org.mockito.stubbing.Stubber;
import org.mockito.stubbing.VoidAnswer1;
import org.mockito.verification.*;
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 java.util.function.Function;

Expand Down Expand Up @@ -107,6 +111,7 @@
* <a href="#51">51. New API for marking classes as unmockable (Since 4.1.0)</a><br/>
* <a href="#52">52. New strictness attribute for @Mock annotation and <code>MockSettings.strictness()</code> methods (Since 4.6.0)</a><br/>
* <a href="#53">53. Specifying mock maker for individual mocks (Since 4.8.0)</a><br/>
* <a href="#54">54. Mocking/spying without specifying class (Since 4.9.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 @@ -1639,6 +1644,23 @@
* Foo mock = Mockito.mock(Foo.class, withSettings().mockMaker(MockMakers.SUBCLASS));
* </code></pre>
*
* <h3 id="54">54. <a class="meaningful_link" href="#mock_without_class" name="mock_without_class">
* Mocking/spying without specifying class</a> (Since 4.9.0)</h3>
*
* Instead of calling method {@link Mockito#mock(Class)} or {@link Mockito#spy(Class)} with Class parameter, you can now
* now call method {@code mock()} or {@code spy()} <strong>without parameters</strong>:
*
* <pre class="code"><code class="java">
* Foo foo = Mockito.mock();
* Bar bar = Mockito.spy();
* </code></pre>
*
* Mockito will automatically detect the needed class.
* <p>
* It works only if you assign result of {@code mock()} or {@code spy()} to a variable or field with an explicit type.
* With an implicit type, the Java compiler is unable to automatically determine the type of a mock and you need
* to pass in the {@code Class} explicitly.
* </p>
*/
@CheckReturnValue
@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -1901,6 +1923,23 @@ public class Mockito extends ArgumentMatchers {
*/
public static final Answer<Object> RETURNS_SELF = Answers.RETURNS_SELF;

/**
* Creates mock object of requested class or interface.
* <p>
* See examples in javadoc for {@link Mockito} class
*
* @param reified don't pass any values to it. It's a trick to detect the class/interface you want to mock.
* @return mock object
* @since 4.9.0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too late, I know, but shouldn't it have been:

Suggested change
* @since 4.9.0
* @since 4.10.0

?

*/
public static <T> T mock(T... reified) {
if (reified.length > 0) {
throw new IllegalArgumentException(
"Please don't pass any values here. Java will detect class automagically.");
}
return mock(getClassOf(reified), withSettings());
}

/**
* Creates mock object of given class or interface.
* <p>
Expand Down Expand Up @@ -2115,6 +2154,25 @@ public static <T> T spy(Class<T> classToSpy) {
classToSpy, withSettings().useConstructor().defaultAnswer(CALLS_REAL_METHODS));
}

/**
* Please refer to the documentation of {@link #spy(Class)}.
*
* @param reified don't pass any values to it. It's a trick to detect the class/interface you want to mock.
* @return spy object
* @since 4.9.0
*/
public static <T> T spy(T... reified) {
if (reified.length > 0) {
throw new IllegalArgumentException(
"Please don't pass any values here. Java will detect class automagically.");
}
return spy(getClassOf(reified));
}

private static <T> Class<T> getClassOf(T[] array) {
return (Class<T>) array.getClass().getComponentType();
}

/**
* 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
Expand Down
40 changes: 40 additions & 0 deletions src/test/java/org/mockito/MockitoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package org.mockito;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.times;
Expand Down Expand Up @@ -133,4 +134,43 @@ public void shouldStartingMockSettingsContainDefaultBehavior() {
// when / then
assertThat(settings.getDefaultAnswer()).isEqualTo(Mockito.RETURNS_DEFAULTS);
}

@Test
@SuppressWarnings({"DoNotMock", "DoNotMockAutoValue"})
public void automaticallyDetectsClassToMock() {
List<String> mock = Mockito.mock();
Mockito.when(mock.size()).thenReturn(42);
assertThat(mock.size()).isEqualTo(42);
}

@Test
@SuppressWarnings({"DoNotMock", "DoNotMockAutoValue"})
public void newMockMethod_shouldNotBeCalledWithParameters() {
assertThatThrownBy(
() -> {
Mockito.mock(asList("1", "2"), asList("3", "4"));
})
.isInstanceOf(IllegalArgumentException.class)
.hasMessageStartingWith("Please don't pass any values here");
}

@Test
@SuppressWarnings({"DoNotMock", "DoNotMockAutoValue"})
public void automaticallyDetectsClassToSpy() {
List<String> mock = Mockito.spy();
Mockito.when(mock.size()).thenReturn(42);
assertThat(mock.size()).isEqualTo(42);
assertThat(mock.get(0)).isNull();
}

@Test
@SuppressWarnings({"DoNotMock", "DoNotMockAutoValue"})
public void newSpyMethod_shouldNotBeCalledWithParameters() {
assertThatThrownBy(
() -> {
Mockito.spy(asList("1", "2"), asList("3", "4"));
})
.isInstanceOf(IllegalArgumentException.class)
.hasMessageStartingWith("Please don't pass any values here");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -339,4 +339,14 @@ class InlineClassTest {

verify(mock).returnsResult()
}

@Test
@SuppressWarnings("DoNotMock", "DoNotMockAutoValue")
fun automaticallyDetectsClassToMock() {
val mock: WithResult = mock()

`when`(mock.returnsResult()).thenReturn(Result.success("OK"))

assertEquals("OK", mock.returnsResult().getOrNull())
}
}