Merge branch '6.2.x'

This commit is contained in:
Sam Brannen
2025-02-12 15:55:33 +01:00
37 changed files with 1106 additions and 208 deletions

View File

@@ -31,9 +31,9 @@ import org.springframework.test.context.bean.override.BeanOverride;
/**
* {@code @MockitoBean} is an annotation that can be used in test classes to
* override beans in a test's
* override a bean in the test's
* {@link org.springframework.context.ApplicationContext ApplicationContext}
* using Mockito mocks.
* with a Mockito mock.
*
* <p>{@code @MockitoBean} can be applied in the following ways.
* <ul>
@@ -49,18 +49,19 @@ import org.springframework.test.context.bean.override.BeanOverride;
* </ul>
*
* <p>When {@code @MockitoBean} is declared on a field, the bean to mock is inferred
* from the type of the annotated field. If multiple candidates exist, a
* {@code @Qualifier} annotation can be declared on the field to help disambiguate.
* In the absence of a {@code @Qualifier} annotation, the name of the annotated
* field will be used as a fallback qualifier. Alternatively, you can explicitly
* specify a bean name to mock by setting the {@link #value() value} or
* {@link #name() name} attribute.
* from the type of the annotated field. If multiple candidates exist in the
* {@code ApplicationContext}, a {@code @Qualifier} annotation can be declared
* on the field to help disambiguate. In the absence of a {@code @Qualifier}
* annotation, the name of the annotated field will be used as a <em>fallback
* qualifier</em>. Alternatively, you can explicitly specify a bean name to mock
* by setting the {@link #value() value} or {@link #name() name} attribute.
*
* <p>When {@code @MockitoBean} is declared at the type level, the type of bean
* to mock must be supplied via the {@link #types() types} attribute. If multiple
* candidates exist, you can explicitly specify a bean name to mock by setting the
* {@link #name() name} attribute. Note, however, that the {@code types} attribute
* must contain a single type if an explicit bean {@code name} is configured.
* (or beans) to mock must be supplied via the {@link #types() types} attribute.
* If multiple candidates exist in the {@code ApplicationContext}, you can
* explicitly specify a bean name to mock by setting the {@link #name() name}
* attribute. Note, however, that the {@code types} attribute must contain a
* single type if an explicit bean {@code name} is configured.
*
* <p>A bean will be created if a corresponding bean does not exist. However, if
* you would like for the test to fail when a corresponding bean does not exist,
@@ -111,7 +112,7 @@ import org.springframework.test.context.bean.override.BeanOverride;
public @interface MockitoBean {
/**
* Alias for {@link #name()}.
* Alias for {@link #name() name}.
* <p>Intended to be used when no other attributes are needed &mdash; for
* example, {@code @MockitoBean("customBeanName")}.
* @see #name()
@@ -136,7 +137,7 @@ public @interface MockitoBean {
* <p>Each type specified will result in a mock being created and registered
* with the {@code ApplicationContext}.
* <p>Types must be omitted when the annotation is used on a field.
* <p>When {@code @MockitoBean} also defines a {@link #name}, this attribute
* <p>When {@code @MockitoBean} also defines a {@link #name name}, this attribute
* can only contain a single value.
* @return the types to mock
* @since 6.2.2

View File

@@ -45,8 +45,10 @@ class MockitoBeanOverrideProcessor implements BeanOverrideProcessor {
"The @MockitoBean 'types' attribute must be omitted when declared on a field");
return new MockitoBeanOverrideHandler(field, ResolvableType.forField(field, testClass), mockitoBean);
}
else if (overrideAnnotation instanceof MockitoSpyBean spyBean) {
return new MockitoSpyBeanOverrideHandler(field, ResolvableType.forField(field, testClass), spyBean);
else if (overrideAnnotation instanceof MockitoSpyBean mockitoSpyBean) {
Assert.state(mockitoSpyBean.types().length == 0,
"The @MockitoSpyBean 'types' attribute must be omitted when declared on a field");
return new MockitoSpyBeanOverrideHandler(field, ResolvableType.forField(field, testClass), mockitoSpyBean);
}
throw new IllegalStateException("""
Invalid annotation passed to MockitoBeanOverrideProcessor: \
@@ -56,21 +58,34 @@ class MockitoBeanOverrideProcessor implements BeanOverrideProcessor {
@Override
public List<BeanOverrideHandler> createHandlers(Annotation overrideAnnotation, Class<?> testClass) {
if (!(overrideAnnotation instanceof MockitoBean mockitoBean)) {
throw new IllegalStateException("""
Invalid annotation passed to MockitoBeanOverrideProcessor: \
expected @MockitoBean on test class """ + testClass.getName());
if (overrideAnnotation instanceof MockitoBean mockitoBean) {
Class<?>[] types = mockitoBean.types();
Assert.state(types.length > 0,
"The @MockitoBean 'types' attribute must not be empty when declared on a class");
Assert.state(mockitoBean.name().isEmpty() || types.length == 1,
"The @MockitoBean 'name' attribute cannot be used when mocking multiple types");
List<BeanOverrideHandler> handlers = new ArrayList<>();
for (Class<?> type : types) {
handlers.add(new MockitoBeanOverrideHandler(ResolvableType.forClass(type), mockitoBean));
}
return handlers;
}
Class<?>[] types = mockitoBean.types();
Assert.state(types.length > 0,
"The @MockitoBean 'types' attribute must not be empty when declared on a class");
Assert.state(mockitoBean.name().isEmpty() || types.length == 1,
"The @MockitoBean 'name' attribute cannot be used when mocking multiple types");
List<BeanOverrideHandler> handlers = new ArrayList<>();
for (Class<?> type : types) {
handlers.add(new MockitoBeanOverrideHandler(ResolvableType.forClass(type), mockitoBean));
else if (overrideAnnotation instanceof MockitoSpyBean mockitoSpyBean) {
Class<?>[] types = mockitoSpyBean.types();
Assert.state(types.length > 0,
"The @MockitoSpyBean 'types' attribute must not be empty when declared on a class");
Assert.state(mockitoSpyBean.name().isEmpty() || types.length == 1,
"The @MockitoSpyBean 'name' attribute cannot be used when mocking multiple types");
List<BeanOverrideHandler> handlers = new ArrayList<>();
for (Class<?> type : types) {
handlers.add(new MockitoSpyBeanOverrideHandler(ResolvableType.forClass(type), mockitoSpyBean));
}
return handlers;
}
return handlers;
throw new IllegalStateException("""
Invalid annotation passed to MockitoBeanOverrideProcessor: \
expected either @MockitoBean or @MockitoSpyBean on test class %s"""
.formatted(testClass.getName()));
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.test.context.bean.override.mockito;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -26,19 +27,40 @@ import org.springframework.core.annotation.AliasFor;
import org.springframework.test.context.bean.override.BeanOverride;
/**
* {@code @MockitoSpyBean} is an annotation that can be applied to a non-static
* field in a test class to override a bean in the test's
* {@code @MockitoSpyBean} is an annotation that can be used in test classes to
* override a bean in the test's
* {@link org.springframework.context.ApplicationContext ApplicationContext}
* with a Mockito spy that wraps the original bean instance.
*
* <p>By default, the bean to spy is inferred from the type of the annotated
* field. If multiple candidates exist, a {@code @Qualifier} annotation can be
* used to help disambiguate. In the absence of a {@code @Qualifier} annotation,
* the name of the annotated field will be used as a fallback qualifier.
* Alternatively, you can explicitly specify a bean name to spy by setting the
* {@link #value() value} or {@link #name() name} attribute. If a bean name is
* specified, it is required that a target bean with that name has been previously
* registered in the application context.
* <p>{@code @MockitoSpyBean} can be applied in the following ways.
* <ul>
* <li>On a non-static field in a test class or any of its superclasses.</li>
* <li>On a non-static field in an enclosing class for a {@code @Nested} test class
* or in any class in the type hierarchy or enclosing class hierarchy above the
* {@code @Nested} test class.</li>
* <li>At the type level on a test class or any superclass or implemented interface
* in the type hierarchy above the test class.</li>
* <li>At the type level on an enclosing class for a {@code @Nested} test class
* or on any class or interface in the type hierarchy or enclosing class hierarchy
* above the {@code @Nested} test class.</li>
* </ul>
*
* <p>When {@code @MockitoSpyBean} is declared on a field, the bean to spy is
* inferred from the type of the annotated field. If multiple candidates exist in
* the {@code ApplicationContext}, a {@code @Qualifier} annotation can be declared
* on the field to help disambiguate. In the absence of a {@code @Qualifier}
* annotation, the name of the annotated field will be used as a <em>fallback
* qualifier</em>. Alternatively, you can explicitly specify a bean name to spy
* by setting the {@link #value() value} or {@link #name() name} attribute. If a
* bean name is specified, it is required that a target bean with that name has
* been previously registered in the application context.
*
* <p>When {@code @MockitoSpyBean} is declared at the type level, the type of bean
* (or beans) to spy must be supplied via the {@link #types() types} attribute.
* If multiple candidates exist in the {@code ApplicationContext}, you can
* explicitly specify a bean name to spy by setting the {@link #name() name}
* attribute. Note, however, that the {@code types} attribute must contain a
* single type if an explicit bean {@code name} is configured.
*
* <p>A spy cannot be created for components which are known to the application
* context but are not beans &mdash; for example, components
@@ -56,24 +78,33 @@ import org.springframework.test.context.bean.override.BeanOverride;
* (default visibility), or {@code private} depending on the needs or coding
* practices of the project.
*
* <p>{@code @MockitoSpyBean} fields will be inherited from an enclosing test class by default.
* See {@link org.springframework.test.context.NestedTestConfiguration @NestedTestConfiguration}
* <p>{@code @MockitoSpyBean} fields and type-level {@code @MockitoSpyBean} declarations
* will be inherited from an enclosing test class by default. See
* {@link org.springframework.test.context.NestedTestConfiguration @NestedTestConfiguration}
* for details.
*
* <p>{@code @MockitoSpyBean} may be used as a <em>meta-annotation</em> to create
* custom <em>composed annotations</em> &mdash; for example, to define common spy
* configuration in a single annotation that can be reused across a test suite.
* {@code @MockitoSpyBean} can also be used as a <em>{@linkplain Repeatable repeatable}</em>
* annotation at the type level &mdash; for example, to spy on several beans by
* {@link #name() name}.
*
* @author Simon Baslé
* @author Sam Brannen
* @since 6.2
* @see org.springframework.test.context.bean.override.mockito.MockitoBean @MockitoBean
* @see org.springframework.test.context.bean.override.convention.TestBean @TestBean
*/
@Target(ElementType.FIELD)
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(MockitoSpyBeans.class)
@BeanOverride(MockitoBeanOverrideProcessor.class)
public @interface MockitoSpyBean {
/**
* Alias for {@link #name()}.
* Alias for {@link #name() name}.
* <p>Intended to be used when no other attributes are needed &mdash; for
* example, {@code @MockitoSpyBean("customBeanName")}.
* @see #name()
@@ -84,13 +115,27 @@ public @interface MockitoSpyBean {
/**
* Name of the bean to spy.
* <p>If left unspecified, the bean to spy is selected according to the
* annotated field's type, taking qualifiers into account if necessary. See
* the {@linkplain MockitoSpyBean class-level documentation} for details.
* configured {@link #types() types} or the annotated field's type, taking
* qualifiers into account if necessary. See the {@linkplain MockitoSpyBean
* class-level documentation} for details.
* @see #value()
*/
@AliasFor("value")
String name() default "";
/**
* One or more types to spy.
* <p>Defaults to none.
* <p>Each type specified will result in a spy being created and registered
* with the {@code ApplicationContext}.
* <p>Types must be omitted when the annotation is used on a field.
* <p>When {@code @MockitoSpyBean} also defines a {@link #name name}, this
* attribute can only contain a single value.
* @return the types to spy
* @since 6.2.3
*/
Class<?>[] types() default {};
/**
* The reset mode to apply to the spied bean.
* <p>The default is {@link MockReset#AFTER} meaning that spies are automatically

View File

@@ -48,7 +48,11 @@ class MockitoSpyBeanOverrideHandler extends AbstractMockitoBeanOverrideHandler {
new SpringAopBypassingVerificationStartedListener();
MockitoSpyBeanOverrideHandler(Field field, ResolvableType typeToSpy, MockitoSpyBean spyBean) {
MockitoSpyBeanOverrideHandler(ResolvableType typeToSpy, MockitoSpyBean spyBean) {
this(null, typeToSpy, spyBean);
}
MockitoSpyBeanOverrideHandler(@Nullable Field field, ResolvableType typeToSpy, MockitoSpyBean spyBean) {
super(field, typeToSpy, (StringUtils.hasText(spyBean.name()) ? spyBean.name() : null),
BeanOverrideStrategy.WRAP, spyBean.reset());
Assert.notNull(typeToSpy, "typeToSpy must not be null");

View File

@@ -0,0 +1,41 @@
/*
* 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;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Container for {@link MockitoSpyBean @MockitoSpyBean} annotations which allows
* {@code @MockitoSpyBean} to be used as a {@linkplain java.lang.annotation.Repeatable
* repeatable annotation} at the type level &mdash; for example, on test classes
* or interfaces implemented by test classes.
*
* @author Sam Brannen
* @since 6.2.3
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MockitoSpyBeans {
MockitoSpyBean[] value();
}

View File

@@ -106,91 +106,197 @@ class MockitoBeanOverrideProcessorTests {
class CreateHandlersTests {
@Test
void missingTypes() {
Class<?> testClass = MissingTypesTestCase.class;
MockitoBean annotation = testClass.getAnnotation(MockitoBean.class);
void otherAnnotationThrows() {
Annotation annotation = getClass().getAnnotation(Nested.class);
assertThatIllegalStateException()
.isThrownBy(() -> processor.createHandlers(annotation, testClass))
.withMessage("The @MockitoBean 'types' attribute must not be empty when declared on a class");
.isThrownBy(() -> processor.createHandlers(annotation, getClass()))
.withMessage("Invalid annotation passed to MockitoBeanOverrideProcessor: expected either " +
"@MockitoBean or @MockitoSpyBean on test class %s", getClass().getName());
}
@Test
void nameNotSupportedWithMultipleTypes() {
Class<?> testClass = NameNotSupportedWithMultipleTypesTestCase.class;
MockitoBean annotation = testClass.getAnnotation(MockitoBean.class);
@Nested
class MockitoBeanTests {
assertThatIllegalStateException()
.isThrownBy(() -> processor.createHandlers(annotation, testClass))
.withMessage("The @MockitoBean 'name' attribute cannot be used when mocking multiple types");
@Test
void missingTypes() {
Class<?> testClass = MissingTypesTestCase.class;
MockitoBean annotation = testClass.getAnnotation(MockitoBean.class);
assertThatIllegalStateException()
.isThrownBy(() -> processor.createHandlers(annotation, testClass))
.withMessage("The @MockitoBean 'types' attribute must not be empty when declared on a class");
}
@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);
}
);
}
@MockitoBean
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 {
}
}
@Test
void singleMockByType() {
Class<?> testClass = SingleMockByTypeTestCase.class;
MockitoBean annotation = testClass.getAnnotation(MockitoBean.class);
List<BeanOverrideHandler> handlers = processor.createHandlers(annotation, testClass);
@Nested
class MockitoSpyBeanTests {
assertThat(handlers).singleElement().isInstanceOfSatisfying(MockitoBeanOverrideHandler.class, handler -> {
assertThat(handler.getField()).isNull();
assertThat(handler.getBeanName()).isNull();
assertThat(handler.getBeanType().resolve()).isEqualTo(Integer.class);
});
@Test
void missingTypes() {
Class<?> testClass = MissingTypesTestCase.class;
MockitoSpyBean annotation = testClass.getAnnotation(MockitoSpyBean.class);
assertThatIllegalStateException()
.isThrownBy(() -> processor.createHandlers(annotation, testClass))
.withMessage("The @MockitoSpyBean 'types' attribute must not be empty when declared on a class");
}
@Test
void nameNotSupportedWithMultipleTypes() {
Class<?> testClass = NameNotSupportedWithMultipleTypesTestCase.class;
MockitoSpyBean annotation = testClass.getAnnotation(MockitoSpyBean.class);
assertThatIllegalStateException()
.isThrownBy(() -> processor.createHandlers(annotation, testClass))
.withMessage("The @MockitoSpyBean 'name' attribute cannot be used when mocking multiple types");
}
@Test
void singleSpyByType() {
Class<?> testClass = SingleSpyByTypeTestCase.class;
MockitoSpyBean annotation = testClass.getAnnotation(MockitoSpyBean.class);
List<BeanOverrideHandler> handlers = processor.createHandlers(annotation, testClass);
assertThat(handlers).singleElement().isInstanceOfSatisfying(MockitoSpyBeanOverrideHandler.class, handler -> {
assertThat(handler.getField()).isNull();
assertThat(handler.getBeanName()).isNull();
assertThat(handler.getBeanType().resolve()).isEqualTo(Integer.class);
});
}
@Test
void singleSpyByName() {
Class<?> testClass = SingleSpyByNameTestCase.class;
MockitoSpyBean annotation = testClass.getAnnotation(MockitoSpyBean.class);
List<BeanOverrideHandler> handlers = processor.createHandlers(annotation, testClass);
assertThat(handlers).singleElement().isInstanceOfSatisfying(MockitoSpyBeanOverrideHandler.class, handler -> {
assertThat(handler.getField()).isNull();
assertThat(handler.getBeanName()).isEqualTo("enigma");
assertThat(handler.getBeanType().resolve()).isEqualTo(Integer.class);
});
}
@Test
void multipleSpies() {
Class<?> testClass = MultipleSpiesTestCase.class;
MockitoSpyBean annotation = testClass.getAnnotation(MockitoSpyBean.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);
}
);
}
@MockitoSpyBean
static class MissingTypesTestCase {
}
@MockitoSpyBean(name = "bogus", types = { Integer.class, Float.class })
static class NameNotSupportedWithMultipleTypesTestCase {
}
@MockitoSpyBean(types = Integer.class)
static class SingleSpyByTypeTestCase {
}
@MockitoSpyBean(name = "enigma", types = Integer.class)
static class SingleSpyByNameTestCase {
}
@MockitoSpyBean(types = { Integer.class, Float.class })
static class MultipleSpiesTestCase {
}
}
@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);
}
);
}
@MockitoBean
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 {
}
}
}

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
@MockitoBean(types = Service01.class)
interface TestInterface01 {
interface MockTestInterface01 {
}

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
@MockitoBean(types = Service08.class)
interface TestInterface08 {
interface MockTestInterface08 {
}

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
@MockitoBean(types = Service11.class)
interface TestInterface11 {
interface MockTestInterface11 {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -30,6 +30,8 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.mockito.MockitoAssertions.assertIsMock;
import static org.springframework.test.mockito.MockitoAssertions.assertIsNotMock;
/**
* Integration tests for {@link MockitoBeans @MockitoBeans} and
@@ -69,12 +71,18 @@ class MockitoBeansByNameIntegrationTests {
@Test
void checkMocksAndStandardBean() {
assertIsMock(s1, "s1");
assertIsMock(s2, "s2");
assertIsMock(service3, "service3");
assertIsNotMock(service4, "service4");
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 {

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
@@ -27,6 +27,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.mockito.MockitoAssertions.assertIsMock;
/**
* Integration tests for {@link MockitoBeans @MockitoBeans} and
@@ -42,7 +43,7 @@ import static org.mockito.BDDMockito.given;
@MockitoBean(types = {Service04.class, Service05.class})
@SharedMocks // Intentionally declared between local @MockitoBean declarations
@MockitoBean(types = Service06.class)
class MockitoBeansByTypeIntegrationTests implements TestInterface01 {
class MockitoBeansByTypeIntegrationTests implements MockTestInterface01 {
@Autowired
Service01 service01;
@@ -79,6 +80,14 @@ class MockitoBeansByTypeIntegrationTests implements TestInterface01 {
@Test
void checkMocks() {
assertIsMock(service01, "service01");
assertIsMock(service02, "service02");
assertIsMock(service03, "service03");
assertIsMock(service04, "service04");
assertIsMock(service05, "service05");
assertIsMock(service06, "service06");
assertIsMock(service07, "service07");
assertThat(service01.greeting()).isEqualTo("mock 01");
assertThat(service02.greeting()).isEqualTo("mock 02");
assertThat(service03.greeting()).isEqualTo("mock 03");
@@ -90,7 +99,7 @@ class MockitoBeansByTypeIntegrationTests implements TestInterface01 {
@MockitoBean(types = Service09.class)
class BaseTestCase implements TestInterface08 {
class BaseTestCase implements MockTestInterface08 {
@Autowired
Service08 service08;
@@ -104,7 +113,7 @@ class MockitoBeansByTypeIntegrationTests implements TestInterface01 {
@Nested
@MockitoBean(types = Service12.class)
class NestedTests extends BaseTestCase implements TestInterface11 {
class NestedTests extends BaseTestCase implements MockTestInterface11 {
@Autowired
Service11 service11;
@@ -128,6 +137,20 @@ class MockitoBeansByTypeIntegrationTests implements TestInterface01 {
@Test
void checkMocks() {
assertIsMock(service01, "service01");
assertIsMock(service02, "service02");
assertIsMock(service03, "service03");
assertIsMock(service04, "service04");
assertIsMock(service05, "service05");
assertIsMock(service06, "service06");
assertIsMock(service07, "service07");
assertIsMock(service08, "service08");
assertIsMock(service09, "service09");
assertIsMock(service10, "service10");
assertIsMock(service11, "service11");
assertIsMock(service12, "service12");
assertIsMock(service13, "service13");
assertThat(service01.greeting()).isEqualTo("mock 01");
assertThat(service02.greeting()).isEqualTo("mock 02");
assertThat(service03.greeting()).isEqualTo("mock 03");

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
import java.util.stream.Stream;

View File

@@ -0,0 +1,127 @@
/*
* 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.typelevel;
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.MockitoSpyBean;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBeans;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.mockito.MockitoAssertions.assertIsNotMock;
import static org.springframework.test.mockito.MockitoAssertions.assertIsNotSpy;
import static org.springframework.test.mockito.MockitoAssertions.assertIsSpy;
/**
* Integration tests for {@link MockitoSpyBeans @MockitoSpyBeans} and
* {@link MockitoSpyBean @MockitoSpyBean} declared "by name" at the class level
* as a repeatable annotation.
*
* @author Sam Brannen
* @since 6.2.3
* @see <a href="https://github.com/spring-projects/spring-framework/issues/34408">gh-34408</a>
* @see MockitoSpyBeansByTypeIntegrationTests
*/
@SpringJUnitConfig
@MockitoSpyBean(name = "s1", types = ExampleService.class)
@MockitoSpyBean(name = "s2", types = ExampleService.class)
class MockitoSpyBeansByNameIntegrationTests {
@Autowired
ExampleService s1;
@Autowired
ExampleService s2;
@MockitoSpyBean(name = "s3")
ExampleService service3;
@Autowired
@Qualifier("s4")
ExampleService service4;
@BeforeEach
void configureSpies() {
given(s1.greeting()).willReturn("spy 1");
given(s2.greeting()).willReturn("spy 2");
given(service3.greeting()).willReturn("spy 3");
}
@Test
void checkSpiesAndStandardBean() {
assertIsSpy(s1, "s1");
assertIsSpy(s2, "s2");
assertIsSpy(service3, "service3");
assertIsNotMock(service4, "service4");
assertIsNotSpy(service4, "service4");
assertThat(s1.greeting()).isEqualTo("spy 1");
assertThat(s2.greeting()).isEqualTo("spy 2");
assertThat(service3.greeting()).isEqualTo("spy 3");
assertThat(service4.greeting()).isEqualTo("prod 4");
}
@Configuration
static class Config {
@Bean
ExampleService s1() {
return new ExampleService() {
@Override
public String greeting() {
return "prod 1";
}
};
}
@Bean
ExampleService s2() {
return new ExampleService() {
@Override
public String greeting() {
return "prod 2";
}
};
}
@Bean
ExampleService s3() {
return new ExampleService() {
@Override
public String greeting() {
return "prod 3";
}
};
}
@Bean
ExampleService s4() {
return () -> "prod 4";
}
}
}

View File

@@ -0,0 +1,307 @@
/*
* 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.typelevel;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBeans;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.mockito.MockitoAssertions.assertIsSpy;
/**
* Integration tests for {@link MockitoSpyBeans @MockitoSpyBeans} and
* {@link MockitoSpyBean @MockitoSpyBean} declared "by type" at the class level,
* as a repeatable annotation, and via a custom composed annotation.
*
* @author Sam Brannen
* @since 6.2.3
* @see <a href="https://github.com/spring-projects/spring-framework/issues/34408">gh-34408</a>
* @see MockitoSpyBeansByNameIntegrationTests
*/
@SpringJUnitConfig
@MockitoSpyBean(types = {Service04.class, Service05.class})
@SharedSpies // Intentionally declared between local @MockitoSpyBean declarations
@MockitoSpyBean(types = Service06.class)
class MockitoSpyBeansByTypeIntegrationTests implements SpyTestInterface01 {
@Autowired
Service01 service01;
@Autowired
Service02 service02;
@Autowired
Service03 service03;
@Autowired
Service04 service04;
@Autowired
Service05 service05;
@Autowired
Service06 service06;
@MockitoSpyBean
Service07 service07;
@BeforeEach
void configureSpies() {
given(service01.greeting()).willReturn("spy 01");
given(service02.greeting()).willReturn("spy 02");
given(service03.greeting()).willReturn("spy 03");
given(service04.greeting()).willReturn("spy 04");
given(service05.greeting()).willReturn("spy 05");
given(service06.greeting()).willReturn("spy 06");
given(service07.greeting()).willReturn("spy 07");
}
@Test
void checkSpies() {
assertIsSpy(service01, "service01");
assertIsSpy(service02, "service02");
assertIsSpy(service03, "service03");
assertIsSpy(service04, "service04");
assertIsSpy(service05, "service05");
assertIsSpy(service06, "service06");
assertIsSpy(service07, "service07");
assertThat(service01.greeting()).isEqualTo("spy 01");
assertThat(service02.greeting()).isEqualTo("spy 02");
assertThat(service03.greeting()).isEqualTo("spy 03");
assertThat(service04.greeting()).isEqualTo("spy 04");
assertThat(service05.greeting()).isEqualTo("spy 05");
assertThat(service06.greeting()).isEqualTo("spy 06");
assertThat(service07.greeting()).isEqualTo("spy 07");
}
@MockitoSpyBean(types = Service09.class)
class BaseTestCase implements SpyTestInterface08 {
@Autowired
Service08 service08;
@Autowired
Service09 service09;
@MockitoSpyBean
Service10 service10;
}
@Nested
@MockitoSpyBean(types = Service12.class)
class NestedTests extends BaseTestCase implements SpyTestInterface11 {
@Autowired
Service11 service11;
@Autowired
Service12 service12;
@MockitoSpyBean
Service13 service13;
@BeforeEach
void configureSpies() {
given(service08.greeting()).willReturn("spy 08");
given(service09.greeting()).willReturn("spy 09");
given(service10.greeting()).willReturn("spy 10");
given(service11.greeting()).willReturn("spy 11");
given(service12.greeting()).willReturn("spy 12");
given(service13.greeting()).willReturn("spy 13");
}
@Test
void checkSpies() {
assertIsSpy(service01, "service01");
assertIsSpy(service02, "service02");
assertIsSpy(service03, "service03");
assertIsSpy(service04, "service04");
assertIsSpy(service05, "service05");
assertIsSpy(service06, "service06");
assertIsSpy(service07, "service07");
assertIsSpy(service08, "service08");
assertIsSpy(service09, "service09");
assertIsSpy(service10, "service10");
assertIsSpy(service11, "service11");
assertIsSpy(service12, "service12");
assertIsSpy(service13, "service13");
assertThat(service01.greeting()).isEqualTo("spy 01");
assertThat(service02.greeting()).isEqualTo("spy 02");
assertThat(service03.greeting()).isEqualTo("spy 03");
assertThat(service04.greeting()).isEqualTo("spy 04");
assertThat(service05.greeting()).isEqualTo("spy 05");
assertThat(service06.greeting()).isEqualTo("spy 06");
assertThat(service07.greeting()).isEqualTo("spy 07");
assertThat(service08.greeting()).isEqualTo("spy 08");
assertThat(service09.greeting()).isEqualTo("spy 09");
assertThat(service10.greeting()).isEqualTo("spy 10");
assertThat(service11.greeting()).isEqualTo("spy 11");
assertThat(service12.greeting()).isEqualTo("spy 12");
assertThat(service13.greeting()).isEqualTo("spy 13");
}
}
@Configuration
static class Config {
@Bean
Service01 service01() {
return new Service01() {
@Override
public String greeting() {
return "prod 1";
}
};
}
@Bean
Service02 service02() {
return new Service02() {
@Override
public String greeting() {
return "prod 2";
}
};
}
@Bean
Service03 service03() {
return new Service03() {
@Override
public String greeting() {
return "prod 3";
}
};
}
@Bean
Service04 service04() {
return new Service04() {
@Override
public String greeting() {
return "prod 4";
}
};
}
@Bean
Service05 service05() {
return new Service05() {
@Override
public String greeting() {
return "prod 5";
}
};
}
@Bean
Service06 service06() {
return new Service06() {
@Override
public String greeting() {
return "prod 6";
}
};
}
@Bean
Service07 service07() {
return new Service07() {
@Override
public String greeting() {
return "prod 7";
}
};
}
@Bean
Service08 service08() {
return new Service08() {
@Override
public String greeting() {
return "prod 8";
}
};
}
@Bean
Service09 service09() {
return new Service09() {
@Override
public String greeting() {
return "prod 9";
}
};
}
@Bean
Service10 service10() {
return new Service10() {
@Override
public String greeting() {
return "prod 10";
}
};
}
@Bean
Service11 service11() {
return new Service11() {
@Override
public String greeting() {
return "prod 11";
}
};
}
@Bean
Service12 service12() {
return new Service12() {
@Override
public String greeting() {
return "prod 12";
}
};
}
@Bean
Service13 service13() {
return new Service13() {
@Override
public String greeting() {
return "prod 13";
}
};
}
}
}

View File

@@ -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.typelevel;
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.MockitoSpyBean;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBeans;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MockitoSpyBeans @MockitoSpyBeans}: {@link MockitoSpyBean @MockitoSpyBean}
* declared at the class level, as a repeatable annotation, and via a custom composed
* annotation.
*
* @author Sam Brannen
* @since 6.2.3
* @see <a href="https://github.com/spring-projects/spring-framework/issues/34408">gh-34408</a>
*/
class MockitoSpyBeansTests {
@Test
void registrationOrderForTopLevelClass() {
Stream<Class<?>> mockedServices = getRegisteredMockTypes(MockitoSpyBeansByTypeIntegrationTests.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(MockitoSpyBeansByTypeIntegrationTests.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);
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service {
String greeting();

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service01 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service02 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service03 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service04 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service05 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service06 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service07 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service08 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service09 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service10 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service11 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service12 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
interface Service13 extends Service {
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.test.context.bean.override.mockito.mockbeans;
package org.springframework.test.context.bean.override.mockito.typelevel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -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.typelevel;
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.MockitoSpyBean;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@MockitoSpyBean(types = Service02.class)
@MockitoSpyBean(types = Service03.class)
@interface SharedSpies {
}

View File

@@ -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.typelevel;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
@MockitoSpyBean(types = Service01.class)
interface SpyTestInterface01 {
}

View File

@@ -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.typelevel;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
@MockitoSpyBean(types = Service08.class)
interface SpyTestInterface08 {
}

View File

@@ -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.typelevel;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
@MockitoSpyBean(types = Service11.class)
interface SpyTestInterface11 {
}

View File

@@ -31,10 +31,12 @@ public abstract class MockitoAssertions {
public static void assertIsMock(Object obj) {
assertThat(isMock(obj)).as("is a Mockito mock").isTrue();
assertIsNotSpy(obj);
}
public static void assertIsMock(Object obj, String message) {
assertThat(isMock(obj)).as("%s is a Mockito mock", message).isTrue();
assertIsNotSpy(obj, message);
}
public static void assertIsNotMock(Object obj) {