diff --git a/docs/src/main/asciidoc/getting-started-testing.adoc b/docs/src/main/asciidoc/getting-started-testing.adoc
index cf621d16d3c22..5332aaa6093ba 100644
--- a/docs/src/main/asciidoc/getting-started-testing.adoc
+++ b/docs/src/main/asciidoc/getting-started-testing.adoc
@@ -828,13 +828,13 @@ Note that there is no dependency on Mockito, you can use any mocking library you
objects to provide the behaviour you require.
NOTE: Using `@Inject` will get you a CDI proxy to the mock instance you install, which is not suitable for passing to methods such as `Mockito.verify`
-which want the mock instance itself. So if you need to call methods such as `verify` you need to hang on to the mock instance in your test, or use `@InjectMock`
-as shown below.
+which want the mock instance itself.
+So if you need to call methods such as `verify` you should hang on to the mock instance in your test, or use `@io.quarkus.test.InjectMock`.
==== Further simplification with `@InjectMock`
Building on the features provided by `QuarkusMock`, Quarkus also allows users to effortlessly take advantage of link:https://site.mockito.org/[Mockito] for mocking the beans supported by `QuarkusMock`.
-This functionality is available via the `@io.quarkus.test.junit.mockito.InjectMock` annotation which is available in the `quarkus-junit5-mockito` dependency.
+This functionality is available with the `@io.quarkus.test.InjectMock` annotation if the `quarkus-junit5-mockito` dependency is present.
Using `@InjectMock`, the previous example could be written as follows:
@@ -938,7 +938,7 @@ public class MockGreetingServiceTest {
<1> Since we configured `greetingService` as a mock, the `GreetingResource` which uses the `GreetingService` bean, we get the mocked response instead of the response of the regular `GreetingService` bean
By default, the `@InjectMock` annotation can be used for any normal CDI scoped bean (e.g. `@ApplicationScoped`, `@RequestScoped`).
-Mocking `@Singleton` beans can be performed by setting the `convertScopes` property to true (such as `@InjectMock(convertScopes = true`).
+Mocking `@Singleton` beans can be performed by adding the `@MockitoConfig(convertScopes = true)` annotation.
This will convert the `@Singleton` bean to an `@ApplicationScoped` bean for the test.
This is considered an advanced option and should only be performed if you fully understand the consequences of changing the scope of the bean.
@@ -1549,8 +1549,8 @@ Then a component test could look like:
import static org.junit.jupiter.api.Assertions.assertEquals;
import jakarta.inject.Inject;
+import io.quarkus.test.InjectMock;
import io.quarkus.test.component.TestConfigProperty;
-import io.quarkus.test.component.TestMock;
import io.quarkus.test.component.QuarkusComponentTest;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -1562,7 +1562,7 @@ public class FooTest {
@Inject
Foo foo; <3>
- @ConfigureMock
+ @InjectMock
Charlie charlieMock; <4>
@Test
@@ -1586,7 +1586,7 @@ The test above could be rewritten like:
import static org.junit.jupiter.api.Assertions.assertEquals;
import jakarta.inject.Inject;
-import io.quarkus.test.component.TestMock;
+import io.quarkus.test.InjectMock;
import io.quarkus.test.component.QuarkusComponentTestExtension;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -1599,7 +1599,7 @@ public class FooTest {
@Inject
Foo foo;
- @ConfigureMock
+ @InjectMock
Charlie charlieMock;
@Test
@@ -1616,7 +1616,7 @@ public class FooTest {
So what exactly does the `QuarkusComponentTest` do?
It starts the CDI container and registers a dedicated xref:config-reference.adoc[configuration object] during the `before all` test phase.
The container is stopped and the config is released during the `after all` test phase.
-The fields annotated with `@Inject` and `@ConfigureMock` are injected after a test instance is created and unset before a test instance is destroyed.
+The fields annotated with `@Inject` and `@InjectMock` are injected after a test instance is created and unset before a test instance is destroyed.
Finally, the CDI request context is activated and terminated per each test method.
NOTE: By default, a new test instance is created for each test method. Therefore, a new CDI container is started for each test method. However, if the test class is annotated with `@org.junit.jupiter.api.TestInstance` and the test instance lifecycle is set to `org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS` then the CDI container will be shared across all test method executions of a given test class.
diff --git a/integration-tests/injectmock/src/test/java/io/quarkus/it/mockbean/RequestScopedFooMockTest.java b/integration-tests/injectmock/src/test/java/io/quarkus/it/mockbean/RequestScopedFooMockTest.java
index c8f369233216a..c36b0f54fe566 100644
--- a/integration-tests/injectmock/src/test/java/io/quarkus/it/mockbean/RequestScopedFooMockTest.java
+++ b/integration-tests/injectmock/src/test/java/io/quarkus/it/mockbean/RequestScopedFooMockTest.java
@@ -6,8 +6,8 @@
import org.junit.jupiter.api.Test;
+import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;
-import io.quarkus.test.junit.mockito.InjectMock;
@QuarkusTest
class RequestScopedFooMockTest {
diff --git a/test-framework/common/src/main/java/io/quarkus/test/InjectMock.java b/test-framework/common/src/main/java/io/quarkus/test/InjectMock.java
new file mode 100644
index 0000000000000..892f52f253786
--- /dev/null
+++ b/test-framework/common/src/main/java/io/quarkus/test/InjectMock.java
@@ -0,0 +1,27 @@
+package io.quarkus.test;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Instructs the test engine to inject a mock instance of a bean in the field of a test class.
+ *
+ * This annotation is supported:
+ *
+ *
in a {@code io.quarkus.test.component.QuarkusComponentTest},
+ *
in a {@code io.quarkus.test.QuarkusTest} if {@code quarkus-junit5-mockito} is present.
+ *
+ * The lifecycle and configuration API of the injected mock depends on the type of test being used.
+ *
+ * Some test types impose additional restrictons and limitations. For example, only beans that have a
+ * client proxy may be mocked in a
+ * {@code io.quarkus.test.junit.QuarkusTest}.
+ */
+@Retention(RUNTIME)
+@Target(FIELD)
+public @interface InjectMock {
+
+}
diff --git a/test-framework/junit5-component/pom.xml b/test-framework/junit5-component/pom.xml
index 934ec6194b6df..4c2f6090b01ea 100644
--- a/test-framework/junit5-component/pom.xml
+++ b/test-framework/junit5-component/pom.xml
@@ -50,6 +50,10 @@
io.quarkusquarkus-core
+
+ io.quarkus
+ quarkus-test-common
+ io.smallrye.commonsmallrye-common-annotation
diff --git a/test-framework/junit5-component/src/main/java/io/quarkus/test/component/ConfigureMock.java b/test-framework/junit5-component/src/main/java/io/quarkus/test/component/ConfigureMock.java
deleted file mode 100644
index b545c0b30362f..0000000000000
--- a/test-framework/junit5-component/src/main/java/io/quarkus/test/component/ConfigureMock.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.quarkus.test.component;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Marks a field of a test class as a target of a mock dependency injection.
- */
-@Retention(RUNTIME)
-@Target(ElementType.FIELD)
-public @interface ConfigureMock {
-
-}
diff --git a/test-framework/junit5-component/src/main/java/io/quarkus/test/component/QuarkusComponentTestExtension.java b/test-framework/junit5-component/src/main/java/io/quarkus/test/component/QuarkusComponentTestExtension.java
index dcba1a67418dc..51e3bec34d887 100644
--- a/test-framework/junit5-component/src/main/java/io/quarkus/test/component/QuarkusComponentTestExtension.java
+++ b/test-framework/junit5-component/src/main/java/io/quarkus/test/component/QuarkusComponentTestExtension.java
@@ -87,6 +87,7 @@
import io.quarkus.arc.processor.Types;
import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.runtime.configuration.ApplicationPropertiesConfigSourceLoader;
+import io.quarkus.test.InjectMock;
import io.smallrye.common.annotation.Experimental;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigBuilder;
@@ -753,11 +754,11 @@ static T cast(Object obj) {
private List injectFields(Class> testClass, Object testInstance) throws Exception {
List> injectAnnotations;
- Class extends Annotation> injectMock = loadInjectMock();
- if (injectMock != null) {
- injectAnnotations = List.of(Inject.class, ConfigureMock.class, injectMock);
+ Class extends Annotation> deprecatedInjectMock = loadDeprecatedInjectMock();
+ if (deprecatedInjectMock != null) {
+ injectAnnotations = List.of(Inject.class, InjectMock.class, deprecatedInjectMock);
} else {
- injectAnnotations = List.of(Inject.class, ConfigureMock.class);
+ injectAnnotations = List.of(Inject.class, InjectMock.class);
}
List injectedFields = new ArrayList<>();
for (Field field : testClass.getDeclaredFields()) {
@@ -839,7 +840,7 @@ void unset(Object testInstance) throws Exception {
}
@SuppressWarnings("unchecked")
- private Class extends Annotation> loadInjectMock() {
+ private Class extends Annotation> loadDeprecatedInjectMock() {
try {
return (Class extends Annotation>) Class.forName("io.quarkus.test.junit.mockito.InjectMock");
} catch (Throwable e) {
diff --git a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/DependencyMockingTest.java b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/DependencyMockingTest.java
index 017307b14bca3..a28f305cd93e3 100644
--- a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/DependencyMockingTest.java
+++ b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/DependencyMockingTest.java
@@ -8,6 +8,7 @@
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.Mockito;
+import io.quarkus.test.InjectMock;
import io.quarkus.test.component.beans.Charlie;
import io.quarkus.test.component.beans.MyComponent;
@@ -21,7 +22,7 @@ public class DependencyMockingTest {
@Inject
MyComponent myComponent;
- @ConfigureMock
+ @InjectMock
Charlie charlie;
@Test
diff --git a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/MockConfiguratorTest.java b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/MockConfiguratorTest.java
index f8daa8eb1b172..c18d9e44fb8f5 100644
--- a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/MockConfiguratorTest.java
+++ b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/MockConfiguratorTest.java
@@ -9,6 +9,7 @@
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.Mockito;
+import io.quarkus.test.InjectMock;
import io.quarkus.test.component.beans.Charlie;
import io.quarkus.test.component.beans.MyComponent;
@@ -24,7 +25,7 @@ public class MockConfiguratorTest {
@Inject
MyComponent myComponent;
- @ConfigureMock
+ @InjectMock
Charlie charlie;
@Test
diff --git a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/MockNotSharedForClassHierarchyTest.java b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/MockNotSharedForClassHierarchyTest.java
index 68901c0a6cfc6..982250daaa7ed 100644
--- a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/MockNotSharedForClassHierarchyTest.java
+++ b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/MockNotSharedForClassHierarchyTest.java
@@ -10,6 +10,8 @@
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.Mockito;
+import io.quarkus.test.InjectMock;
+
public class MockNotSharedForClassHierarchyTest {
@RegisterExtension
@@ -18,7 +20,7 @@ public class MockNotSharedForClassHierarchyTest {
@Inject
Component component;
- @ConfigureMock
+ @InjectMock
Alpha alpha;
@Test
diff --git a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/ObserverInjectingMockTest.java b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/ObserverInjectingMockTest.java
index 3abeb552d0f5f..af369b857d0cc 100644
--- a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/ObserverInjectingMockTest.java
+++ b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/ObserverInjectingMockTest.java
@@ -9,6 +9,7 @@
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.Mockito;
+import io.quarkus.test.InjectMock;
import io.quarkus.test.component.beans.Delta;
import io.quarkus.test.component.beans.MyComponent;
@@ -21,7 +22,7 @@ public class ObserverInjectingMockTest {
@Inject
Event event;
- @ConfigureMock
+ @InjectMock
Delta delta;
@Test
diff --git a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/ProgrammaticLookupMockTest.java b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/ProgrammaticLookupMockTest.java
index 7bd43fcf3aae1..073f14a9c79ec 100644
--- a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/ProgrammaticLookupMockTest.java
+++ b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/ProgrammaticLookupMockTest.java
@@ -10,6 +10,7 @@
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.Mockito;
+import io.quarkus.test.InjectMock;
import io.quarkus.test.component.beans.Delta;
public class ProgrammaticLookupMockTest {
@@ -20,7 +21,7 @@ public class ProgrammaticLookupMockTest {
@Inject
ProgrammaticLookComponent component;
- @ConfigureMock
+ @InjectMock
Delta delta;
@Test
diff --git a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/declarative/DeclarativeDependencyMockingTest.java b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/declarative/DeclarativeDependencyMockingTest.java
index d71eeef0a2b9a..7ff08de26db8f 100644
--- a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/declarative/DeclarativeDependencyMockingTest.java
+++ b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/declarative/DeclarativeDependencyMockingTest.java
@@ -7,7 +7,7 @@
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
-import io.quarkus.test.component.ConfigureMock;
+import io.quarkus.test.InjectMock;
import io.quarkus.test.component.QuarkusComponentTest;
import io.quarkus.test.component.TestConfigProperty;
import io.quarkus.test.component.beans.Charlie;
@@ -20,7 +20,7 @@ public class DeclarativeDependencyMockingTest {
@Inject
MyComponent myComponent;
- @ConfigureMock
+ @InjectMock
Charlie charlie;
@Test
diff --git a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/declarative/ListAllMockTest.java b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/declarative/ListAllMockTest.java
index ddee8d2309ab3..5534cc64c707a 100644
--- a/test-framework/junit5-component/src/test/java/io/quarkus/test/component/declarative/ListAllMockTest.java
+++ b/test-framework/junit5-component/src/test/java/io/quarkus/test/component/declarative/ListAllMockTest.java
@@ -12,7 +12,7 @@
import org.mockito.Mockito;
import io.quarkus.arc.All;
-import io.quarkus.test.component.ConfigureMock;
+import io.quarkus.test.InjectMock;
import io.quarkus.test.component.QuarkusComponentTest;
import io.quarkus.test.component.beans.Bravo;
import io.quarkus.test.component.beans.Delta;
@@ -24,10 +24,10 @@ public class ListAllMockTest {
@Inject
ListAllComponent component;
- @ConfigureMock
+ @InjectMock
Delta delta;
- @ConfigureMock
+ @InjectMock
@SimpleQualifier
Bravo bravo;
diff --git a/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/InjectMock.java b/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/InjectMock.java
index d5d71839015cd..209ec79b45d01 100644
--- a/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/InjectMock.java
+++ b/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/InjectMock.java
@@ -7,8 +7,11 @@
/**
* When used on a field of a test class, the field becomes a Mockito mock,
- * that is then used to mock the normal scoped bean which the field represents
+ * that is then used to mock the normal scoped bean which the field represents.
+ *
+ * @deprecated Use {@link io.quarkus.test.InjectMock} and {@link MockitoConfig} instead.
*/
+@Deprecated(since = "3.2", forRemoval = true)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectMock {
diff --git a/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/MockitoConfig.java b/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/MockitoConfig.java
new file mode 100644
index 0000000000000..44077d60510df
--- /dev/null
+++ b/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/MockitoConfig.java
@@ -0,0 +1,34 @@
+package io.quarkus.test.junit.mockito;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import io.quarkus.test.InjectMock;
+
+/**
+ * This annotation can be used to configure a Mockito mock injected in a field of a test class that is annotated with
+ * {@link InjectMock}. This annotation is only supported in a {@code io.quarkus.test.QuarkusTest}.
+ *
+ * @see InjectMock
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MockitoConfig {
+
+ /**
+ * If true, then Quarkus will change the scope of the target {@code Singleton} bean to {@code ApplicationScoped}
+ * to make it mockable.
+ *
+ * This is an advanced setting and should only be used if you don't rely on the differences between {@code Singleton}
+ * and {@code ApplicationScoped} beans (for example it is invalid to read fields of {@code ApplicationScoped} beans
+ * as a proxy stands in place of the actual implementation)
+ */
+ boolean convertScopes() default false;
+
+ /**
+ * If true, the mock will be created with the {@link org.mockito.Mockito#RETURNS_DEEP_STUBS}
+ */
+ boolean returnsDeepMocks() default false;
+}
diff --git a/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/internal/CreateMockitoMocksCallback.java b/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/internal/CreateMockitoMocksCallback.java
index c1998bae88970..99bfce1995b5e 100644
--- a/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/internal/CreateMockitoMocksCallback.java
+++ b/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/internal/CreateMockitoMocksCallback.java
@@ -16,6 +16,7 @@
import io.quarkus.arc.InstanceHandle;
import io.quarkus.test.junit.callback.QuarkusTestAfterConstructCallback;
import io.quarkus.test.junit.mockito.InjectMock;
+import io.quarkus.test.junit.mockito.MockitoConfig;
public class CreateMockitoMocksCallback implements QuarkusTestAfterConstructCallback {
@@ -24,14 +25,16 @@ public void afterConstruct(Object testInstance) {
Class> current = testInstance.getClass();
while (current.getSuperclass() != null) {
for (Field field : current.getDeclaredFields()) {
- InjectMock injectMockAnnotation = field.getAnnotation(InjectMock.class);
- if (injectMockAnnotation != null) {
- boolean returnsDeepMocks = injectMockAnnotation.returnsDeepMocks();
- InstanceHandle> beanHandle = getBeanHandle(testInstance, field, InjectMock.class);
- Optional