diff --git a/integration-tests/injectmock/src/main/java/io/quarkus/it/mockbean/SameBeanInstance.java b/integration-tests/injectmock/src/main/java/io/quarkus/it/mockbean/SameBeanInstance.java new file mode 100644 index 0000000000000..622f331392b77 --- /dev/null +++ b/integration-tests/injectmock/src/main/java/io/quarkus/it/mockbean/SameBeanInstance.java @@ -0,0 +1,63 @@ +package io.quarkus.it.mockbean; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +public class SameBeanInstance { + + public interface UnderTest { + void method1(); + } + + public interface I3 { + void method3(); + } + + public interface I2 { + void method2(); + } + + public interface I4 { + void method4(); + } + + @ApplicationScoped + public static class C1 implements UnderTest { + @Inject + I2 i2; + + @Inject + I3 i3; + + @Inject + I4 i4; + + @Override + public void method1() { + i2.method2(); + i3.method3(); + } + } + + @ApplicationScoped + public static class C2 implements I2, I3 { + @Override + public void method2() { + + } + + @Override + public void method3() { + + } + } + + @ApplicationScoped + public static class C3 implements I4 { + + @Override + public void method4() { + + } + } +} diff --git a/integration-tests/injectmock/src/test/java/io/quarkus/it/mockbean/SameBeanInstanceTest.java b/integration-tests/injectmock/src/test/java/io/quarkus/it/mockbean/SameBeanInstanceTest.java new file mode 100644 index 0000000000000..4e3724e700143 --- /dev/null +++ b/integration-tests/injectmock/src/test/java/io/quarkus/it/mockbean/SameBeanInstanceTest.java @@ -0,0 +1,35 @@ +package io.quarkus.it.mockbean; + +import static org.mockito.Mockito.*; + +import javax.inject.Inject; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.mockito.InjectMock; + +@QuarkusTest +public class SameBeanInstanceTest { + + @Inject + SameBeanInstance.UnderTest underTest; + + @InjectMock + SameBeanInstance.I2 i2; + + @InjectMock + SameBeanInstance.I3 i3; + + @InjectMock + SameBeanInstance.I4 i4; + + @Test + public void sample() { + underTest.method1(); + + verify(i2).method2(); + verify(i3).method3(); + verify(i4, never()).method4(); + } +} 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 220fbafa3c185..4b85bbdcea43e 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 @@ -4,6 +4,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import javax.inject.Qualifier; @@ -25,15 +26,17 @@ public void afterConstruct(Object testInstance) { InjectMock injectMockAnnotation = field.getAnnotation(InjectMock.class); if (injectMockAnnotation != null) { Object beanInstance = getBeanInstance(testInstance, field, InjectMock.class); - Object mock = createMockAndSetTestField(testInstance, field, beanInstance); - MockitoMocksTracker.track(testInstance, mock, beanInstance); + Optional result = createMockAndSetTestField(testInstance, field, beanInstance); + if (result.isPresent()) { + MockitoMocksTracker.track(testInstance, result.get(), beanInstance); + } } } current = current.getSuperclass(); } } - private Object createMockAndSetTestField(Object testInstance, Field field, Object beanInstance) { + private Optional createMockAndSetTestField(Object testInstance, Field field, Object beanInstance) { Class beanClass = beanInstance.getClass(); // make sure we don't mock proxy classes, especially given that they don't have generics info if (ClientProxy.class.isAssignableFrom(beanClass)) { @@ -41,14 +44,27 @@ private Object createMockAndSetTestField(Object testInstance, Field field, Objec if (beanClass.getSuperclass() != Object.class) beanClass = beanClass.getSuperclass(); } - Object mock = Mockito.mock(beanClass); + Object mock; + boolean isNew; + Optional currentMock = MockitoMocksTracker.currentMock(testInstance, beanInstance); + if (currentMock.isPresent()) { + mock = currentMock.get(); + isNew = false; + } else { + mock = Mockito.mock(beanClass); + isNew = true; + } field.setAccessible(true); try { field.set(testInstance, mock); } catch (IllegalAccessException e) { throw new RuntimeException(e); } - return mock; + if (isNew) { + return Optional.of(mock); + } else { + return Optional.empty(); + } } static Object getBeanInstance(Object testInstance, Field field, Class annotationType) { diff --git a/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/internal/MockitoMocksTracker.java b/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/internal/MockitoMocksTracker.java index 0db8dc76238f1..db816ae9c6ce2 100644 --- a/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/internal/MockitoMocksTracker.java +++ b/test-framework/junit5-mockito/src/main/java/io/quarkus/test/junit/mockito/internal/MockitoMocksTracker.java @@ -3,6 +3,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -27,6 +28,16 @@ static void reset(Object testInstance) { Mockito.reset(getMocks(testInstance).stream().map(o -> o.mock).toArray()); } + static Optional currentMock(Object testInstance, Object beanInstance) { + Set mocks = getMocks(testInstance); + for (Mocked mocked : mocks) { + if (mocked.beanInstance == beanInstance) { + return Optional.of(mocked.mock); + } + } + return Optional.empty(); + } + static class Mocked { final Object mock; final Object beanInstance;