Support @MockitoBean at the type level on test classes
Prior to this commit, @MockitoBean could only be declared on fields within test classes, which prevented developers from being able to easily reuse mock configuration across a test suite. With this commit, @MockitoBean is now supported at the type level on test classes, their superclasses, and interfaces implemented by those classes. @MockitoBean is also supported on enclosing classes for @Nested test classes, their superclasses, and interfaces implemented by those classes, while honoring @NestedTestConfiguration semantics. In addition, @MockitoBean: - has a new `types` attribute that can be used to declare the type or types to mock when @MockitoBean is declared at the type level - can be declared as a repeatable annotation at the type level - can be declared as a meta-annotation on a custom composed annotation which can be reused across a test suite (see the @SharedMocks example in the reference manual) To support these new features, this commit also includes the following changes. - The `field` property in BeanOverrideHandler is now @Nullable. - BeanOverrideProcessor has a new `default` createHandlers() method which is invoked when a @BeanOverride annotation is found at the type level. - MockitoBeanOverrideProcessor implements the new createHandlers() method. - The internal findHandlers() method in BeanOverrideHandler has been completely overhauled. - The @MockitoBean and @MockitoSpyBean section of the reference manual has been completely overhauled. Closes gh-33925
This commit is contained in:
@@ -30,4 +30,8 @@ public abstract class BeanOverrideTestUtils {
|
||||
return BeanOverrideHandler.forTestClass(testClass);
|
||||
}
|
||||
|
||||
public static List<BeanOverrideHandler> findAllHandlers(Class<?> testClass) {
|
||||
return BeanOverrideHandler.findAllHandlers(testClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -67,6 +67,76 @@ class MockitoBeanOverrideHandlerTests {
|
||||
assertThat(handler1).hasSameHashCodeAs(handler2);
|
||||
}
|
||||
|
||||
@Test // gh-33925
|
||||
void isEqualToWithSameInstanceFromClassLevel() {
|
||||
MockitoBeanOverrideHandler handler1 = createHandler(ClassLevelStringMockByName1.class);
|
||||
assertThat(handler1).isEqualTo(handler1);
|
||||
assertThat(handler1).hasSameHashCodeAs(handler1);
|
||||
|
||||
MockitoBeanOverrideHandler handler2 = createHandler(ClassLevelStringMockByType1.class);
|
||||
assertThat(handler2).isEqualTo(handler2);
|
||||
assertThat(handler2).hasSameHashCodeAs(handler2);
|
||||
}
|
||||
|
||||
@Test // gh-33925
|
||||
void isEqualToWithSameByNameLookupMetadataFromClassLevel() {
|
||||
MockitoBeanOverrideHandler handler1 = createHandler(ClassLevelStringMockByName1.class);
|
||||
MockitoBeanOverrideHandler handler2 = createHandler(ClassLevelStringMockByName2.class);
|
||||
assertThat(handler1).isEqualTo(handler2);
|
||||
assertThat(handler2).isEqualTo(handler1);
|
||||
assertThat(handler1).hasSameHashCodeAs(handler2);
|
||||
}
|
||||
|
||||
@Test // gh-33925
|
||||
void isNotEqualToWithDifferentByNameLookupMetadataFromClassLevel() {
|
||||
MockitoBeanOverrideHandler handler1 = createHandler(ClassLevelStringMockByName1.class);
|
||||
MockitoBeanOverrideHandler handler2 = createHandler(ClassLevelStringMockByName3.class);
|
||||
assertThat(handler1).isNotEqualTo(handler2);
|
||||
assertThat(handler2).isNotEqualTo(handler1);
|
||||
assertThat(handler1).doesNotHaveSameHashCodeAs(handler2);
|
||||
}
|
||||
|
||||
@Test // gh-33925
|
||||
void isEqualToWithSameByTypeLookupMetadataFromClassLevel() {
|
||||
MockitoBeanOverrideHandler handler1 = createHandler(ClassLevelStringMockByType1.class);
|
||||
MockitoBeanOverrideHandler handler2 = createHandler(ClassLevelStringMockByType2.class);
|
||||
assertThat(handler1).isEqualTo(handler2);
|
||||
assertThat(handler2).isEqualTo(handler1);
|
||||
assertThat(handler1).hasSameHashCodeAs(handler2);
|
||||
}
|
||||
|
||||
@Test // gh-33925
|
||||
void isNotEqualToWithDifferentByTypeLookupMetadataFromClassLevel() {
|
||||
MockitoBeanOverrideHandler handler1 = createHandler(ClassLevelStringMockByType1.class);
|
||||
MockitoBeanOverrideHandler handler2 = createHandler(ClassLevelStringMockByType3.class);
|
||||
assertThat(handler1).isNotEqualTo(handler2);
|
||||
assertThat(handler2).isNotEqualTo(handler1);
|
||||
assertThat(handler1).doesNotHaveSameHashCodeAs(handler2);
|
||||
}
|
||||
|
||||
@Test // gh-33925
|
||||
void isEqualToWithSameByNameLookupMetadataFromFieldAndClassLevel() {
|
||||
MockitoBeanOverrideHandler handler1 = createHandler(sampleField("service3"));
|
||||
MockitoBeanOverrideHandler handler2 = createHandler(ClassLevelStringMockByName1.class);
|
||||
assertThat(handler1).isEqualTo(handler2);
|
||||
assertThat(handler2).isEqualTo(handler1);
|
||||
assertThat(handler1).hasSameHashCodeAs(handler2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since the "field name as fallback qualifier" is not available for an annotated class,
|
||||
* what would seem to be "equivalent" handlers are actually not considered "equal" when
|
||||
* the the lookup is "by type".
|
||||
*/
|
||||
@Test // gh-33925
|
||||
void isNotEqualToWithSameByTypeLookupMetadataFromFieldAndClassLevel() {
|
||||
MockitoBeanOverrideHandler handler1 = createHandler(sampleField("service"));
|
||||
MockitoBeanOverrideHandler handler2 = createHandler(ClassLevelStringMockByType1.class);
|
||||
assertThat(handler1).isNotEqualTo(handler2);
|
||||
assertThat(handler2).isNotEqualTo(handler1);
|
||||
assertThat(handler1).doesNotHaveSameHashCodeAs(handler2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void isNotEqualEqualToByTypeLookupWithSameMetadataButDifferentField() {
|
||||
MockitoBeanOverrideHandler handler1 = createHandler(sampleField("service"));
|
||||
@@ -122,6 +192,11 @@ class MockitoBeanOverrideHandlerTests {
|
||||
return new MockitoBeanOverrideHandler(field, ResolvableType.forClass(field.getType()), annotation);
|
||||
}
|
||||
|
||||
private MockitoBeanOverrideHandler createHandler(Class<?> clazz) {
|
||||
MockitoBean annotation = AnnotatedElementUtils.getMergedAnnotation(clazz, MockitoBean.class);
|
||||
return new MockitoBeanOverrideHandler(null, ResolvableType.forClass(annotation.types()[0]), annotation);
|
||||
}
|
||||
|
||||
|
||||
static class SampleOneMock {
|
||||
|
||||
@@ -159,4 +234,28 @@ class MockitoBeanOverrideHandlerTests {
|
||||
private String service7;
|
||||
}
|
||||
|
||||
@MockitoBean(name = "beanToMock", types = String.class)
|
||||
static class ClassLevelStringMockByName1 {
|
||||
}
|
||||
|
||||
@MockitoBean(name = "beanToMock", types = String.class)
|
||||
static class ClassLevelStringMockByName2 {
|
||||
}
|
||||
|
||||
@MockitoBean(name = "otherBeanToMock", types = String.class)
|
||||
static class ClassLevelStringMockByName3 {
|
||||
}
|
||||
|
||||
@MockitoBean(types = String.class)
|
||||
static class ClassLevelStringMockByType1 {
|
||||
}
|
||||
|
||||
@MockitoBean(types = String.class)
|
||||
static class ClassLevelStringMockByType2 {
|
||||
}
|
||||
|
||||
@MockitoBean(types = Integer.class)
|
||||
static class ClassLevelStringMockByType3 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ package org.springframework.test.context.bean.override.mockito;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -41,43 +43,155 @@ class MockitoBeanOverrideProcessorTests {
|
||||
private final MockitoBeanOverrideProcessor processor = new MockitoBeanOverrideProcessor();
|
||||
|
||||
|
||||
private final Field field = ReflectionUtils.findField(TestCase.class, "number");
|
||||
@Nested
|
||||
class CreateHandlerTests {
|
||||
|
||||
private final Field field = ReflectionUtils.findField(TestCase.class, "number");
|
||||
|
||||
|
||||
@Test
|
||||
void mockAnnotationCreatesMockitoBeanOverrideHandler() {
|
||||
MockitoBean annotation = AnnotationUtils.synthesizeAnnotation(MockitoBean.class);
|
||||
BeanOverrideHandler object = processor.createHandler(annotation, TestCase.class, field);
|
||||
@Test
|
||||
void mockAnnotationCreatesMockitoBeanOverrideHandler() {
|
||||
MockitoBean annotation = AnnotationUtils.synthesizeAnnotation(MockitoBean.class);
|
||||
BeanOverrideHandler object = processor.createHandler(annotation, TestCase.class, field);
|
||||
|
||||
assertThat(object).isExactlyInstanceOf(MockitoBeanOverrideHandler.class);
|
||||
assertThat(object).isExactlyInstanceOf(MockitoBeanOverrideHandler.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void spyAnnotationCreatesMockitoSpyBeanOverrideHandler() {
|
||||
MockitoSpyBean annotation = AnnotationUtils.synthesizeAnnotation(MockitoSpyBean.class);
|
||||
BeanOverrideHandler object = processor.createHandler(annotation, TestCase.class, field);
|
||||
|
||||
assertThat(object).isExactlyInstanceOf(MockitoSpyBeanOverrideHandler.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void otherAnnotationThrows() {
|
||||
Annotation annotation = field.getAnnotation(Nullable.class);
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> processor.createHandler(annotation, TestCase.class, field))
|
||||
.withMessage("Invalid annotation passed to MockitoBeanOverrideProcessor: expected either " +
|
||||
"@MockitoBean or @MockitoSpyBean on field %s.%s", field.getDeclaringClass().getName(),
|
||||
field.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void typesNotSupportedAtFieldLevel() {
|
||||
Field field = ReflectionUtils.findField(TestCase.class, "typesNotSupported");
|
||||
MockitoBean annotation = field.getAnnotation(MockitoBean.class);
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> processor.createHandler(annotation, TestCase.class, field))
|
||||
.withMessage("The @MockitoBean 'types' attribute must be omitted when declared on a field");
|
||||
}
|
||||
|
||||
|
||||
static class TestCase {
|
||||
|
||||
@Nullable
|
||||
@MockitoBean
|
||||
@MockitoSpyBean
|
||||
Integer number;
|
||||
|
||||
@MockitoBean(types = Integer.class)
|
||||
String typesNotSupported;
|
||||
}
|
||||
|
||||
@MockitoBean(name = "bogus", types = Integer.class)
|
||||
static class NameNotSupportedTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void spyAnnotationCreatesMockitoSpyBeanOverrideHandler() {
|
||||
MockitoSpyBean annotation = AnnotationUtils.synthesizeAnnotation(MockitoSpyBean.class);
|
||||
BeanOverrideHandler object = processor.createHandler(annotation, TestCase.class, field);
|
||||
@Nested
|
||||
class CreateHandlersTests {
|
||||
|
||||
assertThat(object).isExactlyInstanceOf(MockitoSpyBeanOverrideHandler.class);
|
||||
}
|
||||
@Test
|
||||
void missingTypes() {
|
||||
Class<?> testClass = MissingTypesTestCase.class;
|
||||
MockitoBean annotation = testClass.getAnnotation(MockitoBean.class);
|
||||
|
||||
@Test
|
||||
void otherAnnotationThrows() {
|
||||
Annotation annotation = field.getAnnotation(Nullable.class);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> processor.createHandlers(annotation, testClass))
|
||||
.withMessage("The @MockitoBean 'types' attribute must not be empty when declared on a class");
|
||||
}
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> processor.createHandler(annotation, TestCase.class, field))
|
||||
.withMessage("Invalid annotation passed to MockitoBeanOverrideProcessor: expected either " +
|
||||
"@MockitoBean or @MockitoSpyBean on field %s.%s", field.getDeclaringClass().getName(),
|
||||
field.getName());
|
||||
}
|
||||
@Test
|
||||
void nameNotSupportedWithMultipleTypes() {
|
||||
Class<?> testClass = NameNotSupportedWithMultipleTypesTestCase.class;
|
||||
MockitoBean annotation = testClass.getAnnotation(MockitoBean.class);
|
||||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> processor.createHandlers(annotation, testClass))
|
||||
.withMessage("The @MockitoBean 'name' attribute cannot be used when mocking multiple types");
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleMockByType() {
|
||||
Class<?> testClass = SingleMockByTypeTestCase.class;
|
||||
MockitoBean annotation = testClass.getAnnotation(MockitoBean.class);
|
||||
List<BeanOverrideHandler> handlers = processor.createHandlers(annotation, testClass);
|
||||
|
||||
assertThat(handlers).singleElement().isInstanceOfSatisfying(MockitoBeanOverrideHandler.class, handler -> {
|
||||
assertThat(handler.getField()).isNull();
|
||||
assertThat(handler.getBeanName()).isNull();
|
||||
assertThat(handler.getBeanType().resolve()).isEqualTo(Integer.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleMockByName() {
|
||||
Class<?> testClass = SingleMockByNameTestCase.class;
|
||||
MockitoBean annotation = testClass.getAnnotation(MockitoBean.class);
|
||||
List<BeanOverrideHandler> handlers = processor.createHandlers(annotation, testClass);
|
||||
|
||||
assertThat(handlers).singleElement().isInstanceOfSatisfying(MockitoBeanOverrideHandler.class, handler -> {
|
||||
assertThat(handler.getField()).isNull();
|
||||
assertThat(handler.getBeanName()).isEqualTo("enigma");
|
||||
assertThat(handler.getBeanType().resolve()).isEqualTo(Integer.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipleMocks() {
|
||||
Class<?> testClass = MultipleMocksTestCase.class;
|
||||
MockitoBean annotation = testClass.getAnnotation(MockitoBean.class);
|
||||
List<BeanOverrideHandler> handlers = processor.createHandlers(annotation, testClass);
|
||||
|
||||
assertThat(handlers).satisfiesExactly(
|
||||
handler1 -> {
|
||||
assertThat(handler1.getField()).isNull();
|
||||
assertThat(handler1.getBeanName()).isNull();
|
||||
assertThat(handler1.getBeanType().resolve()).isEqualTo(Integer.class);
|
||||
},
|
||||
handler2 -> {
|
||||
assertThat(handler2.getField()).isNull();
|
||||
assertThat(handler2.getBeanName()).isNull();
|
||||
assertThat(handler2.getBeanType().resolve()).isEqualTo(Float.class);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static class TestCase {
|
||||
|
||||
@Nullable
|
||||
@MockitoBean
|
||||
@MockitoSpyBean
|
||||
Integer number;
|
||||
static class MissingTypesTestCase {
|
||||
}
|
||||
|
||||
@MockitoBean(name = "bogus", types = { Integer.class, Float.class })
|
||||
static class NameNotSupportedWithMultipleTypesTestCase {
|
||||
}
|
||||
|
||||
@MockitoBean(types = Integer.class)
|
||||
static class SingleMockByTypeTestCase {
|
||||
}
|
||||
|
||||
@MockitoBean(name = "enigma", types = Integer.class)
|
||||
static class SingleMockByNameTestCase {
|
||||
}
|
||||
|
||||
@MockitoBean(types = { Integer.class, Float.class })
|
||||
static class MultipleMocksTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.bean.override.example.ExampleService;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBeans;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MockitoBeans @MockitoBeans} and
|
||||
* {@link MockitoBean @MockitoBean} declared "by name" at the class level as a
|
||||
* repeatable annotation.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.2.2
|
||||
* @see <a href="https://github.com/spring-projects/spring-framework/issues/33925">gh-33925</a>
|
||||
* @see MockitoBeansByTypeIntegrationTests
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
@MockitoBean(name = "s1", types = ExampleService.class)
|
||||
@MockitoBean(name = "s2", types = ExampleService.class)
|
||||
class MockitoBeansByNameIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
ExampleService s1;
|
||||
|
||||
@Autowired
|
||||
ExampleService s2;
|
||||
|
||||
@MockitoBean(name = "s3")
|
||||
ExampleService service3;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("s4")
|
||||
ExampleService service4;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void configureMocks() {
|
||||
given(s1.greeting()).willReturn("mock 1");
|
||||
given(s2.greeting()).willReturn("mock 2");
|
||||
given(service3.greeting()).willReturn("mock 3");
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkMocksAndStandardBean() {
|
||||
assertThat(s1.greeting()).isEqualTo("mock 1");
|
||||
assertThat(s2.greeting()).isEqualTo("mock 2");
|
||||
assertThat(service3.greeting()).isEqualTo("mock 3");
|
||||
assertThat(service4.greeting()).isEqualTo("prod 4");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
ExampleService s1() {
|
||||
return () -> "prod 1";
|
||||
}
|
||||
|
||||
@Bean
|
||||
ExampleService s2() {
|
||||
return () -> "prod 2";
|
||||
}
|
||||
|
||||
@Bean
|
||||
ExampleService s3() {
|
||||
return () -> "prod 3";
|
||||
}
|
||||
|
||||
@Bean
|
||||
ExampleService s4() {
|
||||
return () -> "prod 4";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBeans;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link MockitoBeans @MockitoBeans} and
|
||||
* {@link MockitoBean @MockitoBean} declared "by type" at the class level, as a
|
||||
* repeatable annotation, and via a custom composed annotation.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.2.2
|
||||
* @see <a href="https://github.com/spring-projects/spring-framework/issues/33925">gh-33925</a>
|
||||
* @see MockitoBeansByNameIntegrationTests
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
@MockitoBean(types = {Service04.class, Service05.class})
|
||||
@SharedMocks // Intentionally declared between local @MockitoBean declarations
|
||||
@MockitoBean(types = Service06.class)
|
||||
class MockitoBeansByTypeIntegrationTests implements TestInterface01 {
|
||||
|
||||
@Autowired
|
||||
Service01 service01;
|
||||
|
||||
@Autowired
|
||||
Service02 service02;
|
||||
|
||||
@Autowired
|
||||
Service03 service03;
|
||||
|
||||
@Autowired
|
||||
Service04 service04;
|
||||
|
||||
@Autowired
|
||||
Service05 service05;
|
||||
|
||||
@Autowired
|
||||
Service06 service06;
|
||||
|
||||
@MockitoBean
|
||||
Service07 service07;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void configureMocks() {
|
||||
given(service01.greeting()).willReturn("mock 01");
|
||||
given(service02.greeting()).willReturn("mock 02");
|
||||
given(service03.greeting()).willReturn("mock 03");
|
||||
given(service04.greeting()).willReturn("mock 04");
|
||||
given(service05.greeting()).willReturn("mock 05");
|
||||
given(service06.greeting()).willReturn("mock 06");
|
||||
given(service07.greeting()).willReturn("mock 07");
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkMocks() {
|
||||
assertThat(service01.greeting()).isEqualTo("mock 01");
|
||||
assertThat(service02.greeting()).isEqualTo("mock 02");
|
||||
assertThat(service03.greeting()).isEqualTo("mock 03");
|
||||
assertThat(service04.greeting()).isEqualTo("mock 04");
|
||||
assertThat(service05.greeting()).isEqualTo("mock 05");
|
||||
assertThat(service06.greeting()).isEqualTo("mock 06");
|
||||
assertThat(service07.greeting()).isEqualTo("mock 07");
|
||||
}
|
||||
|
||||
|
||||
@MockitoBean(types = Service09.class)
|
||||
static class BaseTestCase implements TestInterface08 {
|
||||
|
||||
@Autowired
|
||||
Service08 service08;
|
||||
|
||||
@Autowired
|
||||
Service09 service09;
|
||||
|
||||
@MockitoBean
|
||||
Service10 service10;
|
||||
}
|
||||
|
||||
@Nested
|
||||
@MockitoBean(types = Service12.class)
|
||||
class NestedTests extends BaseTestCase implements TestInterface11 {
|
||||
|
||||
@Autowired
|
||||
Service11 service11;
|
||||
|
||||
@Autowired
|
||||
Service12 service12;
|
||||
|
||||
@MockitoBean
|
||||
Service13 service13;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void configureMocks() {
|
||||
given(service08.greeting()).willReturn("mock 08");
|
||||
given(service09.greeting()).willReturn("mock 09");
|
||||
given(service10.greeting()).willReturn("mock 10");
|
||||
given(service11.greeting()).willReturn("mock 11");
|
||||
given(service12.greeting()).willReturn("mock 12");
|
||||
given(service13.greeting()).willReturn("mock 13");
|
||||
}
|
||||
|
||||
@Test
|
||||
void checkMocks() {
|
||||
assertThat(service01.greeting()).isEqualTo("mock 01");
|
||||
assertThat(service02.greeting()).isEqualTo("mock 02");
|
||||
assertThat(service03.greeting()).isEqualTo("mock 03");
|
||||
assertThat(service04.greeting()).isEqualTo("mock 04");
|
||||
assertThat(service05.greeting()).isEqualTo("mock 05");
|
||||
assertThat(service06.greeting()).isEqualTo("mock 06");
|
||||
assertThat(service07.greeting()).isEqualTo("mock 07");
|
||||
assertThat(service08.greeting()).isEqualTo("mock 08");
|
||||
assertThat(service09.greeting()).isEqualTo("mock 09");
|
||||
assertThat(service10.greeting()).isEqualTo("mock 10");
|
||||
assertThat(service11.greeting()).isEqualTo("mock 11");
|
||||
assertThat(service12.greeting()).isEqualTo("mock 12");
|
||||
assertThat(service13.greeting()).isEqualTo("mock 13");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.test.context.bean.override.BeanOverrideHandler;
|
||||
import org.springframework.test.context.bean.override.BeanOverrideTestUtils;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBeans;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link MockitoBeans @MockitoBeans}: {@link MockitoBean @MockitoBean}
|
||||
* declared at the class level, as a repeatable annotation, and via a custom composed
|
||||
* annotation.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.2.2
|
||||
* @see <a href="https://github.com/spring-projects/spring-framework/issues/33925">gh-33925</a>
|
||||
*/
|
||||
class MockitoBeansTests {
|
||||
|
||||
@Test
|
||||
void registrationOrderForTopLevelClass() {
|
||||
Stream<Class<?>> mockedServices = getRegisteredMockTypes(MockitoBeansByTypeIntegrationTests.class);
|
||||
assertThat(mockedServices).containsExactly(
|
||||
Service01.class, Service02.class, Service03.class, Service04.class,
|
||||
Service05.class, Service06.class, Service07.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registrationOrderForNestedClass() {
|
||||
Stream<Class<?>> mockedServices = getRegisteredMockTypes(MockitoBeansByTypeIntegrationTests.NestedTests.class);
|
||||
assertThat(mockedServices).containsExactly(
|
||||
Service01.class, Service02.class, Service03.class, Service04.class,
|
||||
Service05.class, Service06.class, Service07.class, Service08.class,
|
||||
Service09.class, Service10.class, Service11.class, Service12.class,
|
||||
Service13.class);
|
||||
}
|
||||
|
||||
|
||||
private static Stream<Class<?>> getRegisteredMockTypes(Class<?> testClass) {
|
||||
return BeanOverrideTestUtils.findAllHandlers(testClass)
|
||||
.stream()
|
||||
.map(BeanOverrideHandler::getBeanType)
|
||||
.map(ResolvableType::getRawClass);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service {
|
||||
String greeting();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service01 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service02 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service03 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service04 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service05 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service06 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service07 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service08 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service09 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service10 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service11 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service12 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
interface Service13 extends Service {
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@MockitoBean(types = Service02.class)
|
||||
@MockitoBean(types = Service03.class)
|
||||
@interface SharedMocks {
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
@MockitoBean(types = Service01.class)
|
||||
interface TestInterface01 {
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
@MockitoBean(types = Service08.class)
|
||||
interface TestInterface08 {
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context.bean.override.mockito.mockbeans;
|
||||
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
@MockitoBean(types = Service11.class)
|
||||
interface TestInterface11 {
|
||||
}
|
||||
Reference in New Issue
Block a user