Revise bean override tests with a focus on AOT support
As a follow up to the previous commit (31f8e12adb
), this commit
polishes bean override tests and revises them with a focus on AOT
testing support and simplified maintenance.
- Introduce EngineTestKitUtils to simplify working with JUnit's
EngineTestKit.
- Use idiomatic EngineTestKit APIs to simplify assertions on
EngineTestKit results.
- Introduce BeanOverrideTestSuite to simplify running all bean override
tests within the IDE.
- Separate failure and success scenario tests, so that failure tests do
not launch the JUnit Platform to run tests using the Spring
TestContext Framework (TCF) within a test class that itself uses the
TCF.
- Make AbstractTestBeanIntegrationTestCase actually abstract.
- Rename test case classes to give them meaningful names and simplify
understanding of what's being tested.
- Ensure tests for @MockitoSpyBean functionality use @MockitoSpyBean
instead of @MockitoBean.
- Declare @Configuration classes local to @SpringJUnitConfig test
classes whenever possible.
See gh-29122
See gh-32925
This commit is contained in:
parent
31f8e12adb
commit
87c93d35d6
|
@ -133,7 +133,7 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
|||
Set<String> candidates = getExistingBeanNamesByType(beanFactory, overrideMetadata, true);
|
||||
if (candidates.size() != 1) {
|
||||
Field f = overrideMetadata.getField();
|
||||
throw new IllegalStateException("Unable to select a bean definition to override, " +
|
||||
throw new IllegalStateException("Unable to select a bean definition to override: " +
|
||||
candidates.size() + " bean definitions found of type " + overrideMetadata.getBeanType() +
|
||||
" (as required by annotated field '" + f.getDeclaringClass().getSimpleName() +
|
||||
"." + f.getName() + "')");
|
||||
|
@ -147,7 +147,7 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
|||
existingBeanDefinition = beanFactory.getBeanDefinition(beanName);
|
||||
}
|
||||
else if (enforceExistingDefinition) {
|
||||
throw new IllegalStateException("Unable to override bean '" + beanName + "'; there is no" +
|
||||
throw new IllegalStateException("Unable to override bean '" + beanName + "': there is no" +
|
||||
" bean definition to replace with that name of type " + overrideMetadata.getBeanType());
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
|||
Set<String> candidateNames = getExistingBeanNamesByType(beanFactory, metadata, true);
|
||||
if (candidateNames.size() != 1) {
|
||||
Field f = metadata.getField();
|
||||
throw new IllegalStateException("Unable to select a bean to override by wrapping, " +
|
||||
throw new IllegalStateException("Unable to select a bean to override by wrapping: " +
|
||||
candidateNames.size() + " bean instances found of type " + metadata.getBeanType() +
|
||||
" (as required by annotated field '" + f.getDeclaringClass().getSimpleName() +
|
||||
"." + f.getName() + "')");
|
||||
|
@ -193,7 +193,7 @@ class BeanOverrideBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
|
|||
else {
|
||||
Set<String> candidates = getExistingBeanNamesByType(beanFactory, metadata, false);
|
||||
if (!candidates.contains(beanName)) {
|
||||
throw new IllegalStateException("Unable to override bean '" + beanName + "' by wrapping; there is no" +
|
||||
throw new IllegalStateException("Unable to override bean '" + beanName + "' by wrapping: there is no" +
|
||||
" existing bean instance with that name of type " + metadata.getBeanType());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ class BeanOverrideBeanFactoryPostProcessorTests {
|
|||
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(context::refresh)
|
||||
.withMessage("Unable to override bean 'explicit'; there is no bean definition " +
|
||||
.withMessage("Unable to override bean 'explicit': there is no bean definition " +
|
||||
"to replace with that name of type org.springframework.test.context.bean.override.example.ExampleService");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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;
|
||||
|
||||
import org.junit.jupiter.api.ClassOrderer;
|
||||
import org.junit.platform.suite.api.ConfigurationParameter;
|
||||
import org.junit.platform.suite.api.ExcludeTags;
|
||||
import org.junit.platform.suite.api.IncludeClassNamePatterns;
|
||||
import org.junit.platform.suite.api.IncludeEngines;
|
||||
import org.junit.platform.suite.api.SelectPackages;
|
||||
import org.junit.platform.suite.api.Suite;
|
||||
|
||||
/**
|
||||
* JUnit Platform based test suite for tests that involve bean override support
|
||||
* in the Spring TestContext Framework.
|
||||
*
|
||||
* <p><strong>This suite is only intended to be used manually within an IDE.</strong>
|
||||
*
|
||||
* <h3>Logging Configuration</h3>
|
||||
*
|
||||
* <p>In order for our log4j2 configuration to be used in an IDE, you must
|
||||
* set the following system property before running any tests — for
|
||||
* example, in <em>Run Configurations</em> in Eclipse.
|
||||
*
|
||||
* <pre style="code">
|
||||
* -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager
|
||||
* </pre>
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
*/
|
||||
@Suite
|
||||
@IncludeEngines("junit-jupiter")
|
||||
@SelectPackages("org.springframework.test.context.bean.override")
|
||||
@IncludeClassNamePatterns(".*Tests$")
|
||||
@ExcludeTags("failing-test-case")
|
||||
@ConfigurationParameter(
|
||||
key = ClassOrderer.DEFAULT_ORDER_PROPERTY_NAME,
|
||||
value = "org.junit.jupiter.api.ClassOrderer$ClassName"
|
||||
)
|
||||
public class BeanOverrideTestSuite {
|
||||
}
|
|
@ -21,28 +21,28 @@ import org.springframework.context.annotation.Configuration;
|
|||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
@SpringJUnitConfig
|
||||
class AbstractTestBeanIntegrationTestCase {
|
||||
abstract class AbstractTestBeanIntegrationTestCase {
|
||||
|
||||
@TestBean(name = "someBean")
|
||||
Pojo someBean;
|
||||
@TestBean(name = "someBean")
|
||||
Pojo someBean;
|
||||
|
||||
@TestBean(name = "otherBean")
|
||||
Pojo otherBean;
|
||||
@TestBean(name = "otherBean")
|
||||
Pojo otherBean;
|
||||
|
||||
@TestBean(name = "thirdBean")
|
||||
Pojo anotherBean;
|
||||
@TestBean(name = "thirdBean")
|
||||
Pojo anotherBean;
|
||||
|
||||
static Pojo otherBeanTestOverride() {
|
||||
return new FakePojo("otherBean in superclass");
|
||||
}
|
||||
static Pojo otherBeanTestOverride() {
|
||||
return new FakePojo("otherBean in superclass");
|
||||
}
|
||||
|
||||
static Pojo thirdBeanTestOverride() {
|
||||
return new FakePojo("third in superclass");
|
||||
}
|
||||
static Pojo thirdBeanTestOverride() {
|
||||
return new FakePojo("third in superclass");
|
||||
}
|
||||
|
||||
static Pojo commonBeanOverride() {
|
||||
return new FakePojo("in superclass");
|
||||
}
|
||||
static Pojo commonBeanOverride() {
|
||||
return new FakePojo("in superclass");
|
||||
}
|
||||
|
||||
interface Pojo {
|
||||
|
||||
|
@ -60,6 +60,7 @@ class AbstractTestBeanIntegrationTestCase {
|
|||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
@ -94,4 +95,5 @@ class AbstractTestBeanIntegrationTestCase {
|
|||
return new ProdPojo();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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.convention;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
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.example.RealExampleService;
|
||||
import org.springframework.test.context.junit.EngineTestKitUtils;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message;
|
||||
|
||||
/**
|
||||
* {@link TestBean @TestBean} "by type" integration tests for failure scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see TestBeanByTypeIntegrationTests
|
||||
*/
|
||||
class FailingTestBeanByTypeIntegrationTests {
|
||||
|
||||
@Test
|
||||
void zeroCandidates() {
|
||||
Class<?> testClass = NoMatchingBeansTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
cause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to select a bean definition to override: 0 bean definitions \
|
||||
found of type %s (as required by annotated field '%s.example')"""
|
||||
.formatted(ExampleService.class.getName(), testClass.getSimpleName())))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tooManyCandidates() {
|
||||
Class<?> testClass = TooManyBeansTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
cause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to select a bean definition to override: 2 bean definitions \
|
||||
found of type %s (as required by annotated field '%s.example')"""
|
||||
.formatted(ExampleService.class.getName(), testClass.getSimpleName())))));
|
||||
}
|
||||
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class NoMatchingBeansTestCase {
|
||||
|
||||
@TestBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
}
|
||||
|
||||
static ExampleService exampleTestOverride() {
|
||||
return fail("unexpected override");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class TooManyBeansTestCase {
|
||||
|
||||
@TestBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
}
|
||||
|
||||
static ExampleService exampleTestOverride() {
|
||||
return fail("unexpected override");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
ExampleService bean1() {
|
||||
return new RealExampleService("1 Hello");
|
||||
}
|
||||
|
||||
@Bean
|
||||
ExampleService bean2() {
|
||||
return new RealExampleService("2 Hello");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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.convention;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.test.context.junit.EngineTestKitUtils;
|
||||
|
||||
import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message;
|
||||
import static org.springframework.test.context.junit.EngineTestKitUtils.rootCause;
|
||||
|
||||
/**
|
||||
* {@link TestBean @TestBean} inheritance integration tests for failure scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see TestBeanInheritanceIntegrationTests
|
||||
*/
|
||||
class FailingTestBeanInheritanceIntegrationTests {
|
||||
|
||||
@Test
|
||||
void failsIfFieldInSupertypeButNoMethod() {
|
||||
Class<?> testClass = FieldInSupertypeButNoMethodTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
rootCause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Failed to find a static test bean factory method in %s with return type %s \
|
||||
whose name matches one of the supported candidates [someBeanTestOverride]"""
|
||||
.formatted(testClass.getName(), AbstractTestBeanIntegrationTestCase.Pojo.class.getName())))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void failsIfMethod1InSupertypeAndMethod2InType() {
|
||||
Class<?> testClass = Method1InSupertypeAndMethod2InTypeTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
rootCause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Found 2 competing static test bean factory methods in %s with return type %s \
|
||||
whose name matches one of the supported candidates \
|
||||
[thirdBeanTestOverride, anotherBeanTestOverride]"""
|
||||
.formatted(testClass.getName(), AbstractTestBeanIntegrationTestCase.Pojo.class.getName())))));
|
||||
}
|
||||
|
||||
|
||||
static class FieldInSupertypeButNoMethodTestCase extends AbstractTestBeanIntegrationTestCase {
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
}
|
||||
}
|
||||
|
||||
static class Method1InSupertypeAndMethod2InTypeTestCase extends AbstractTestBeanIntegrationTestCase {
|
||||
|
||||
static Pojo someBeanTestOverride() {
|
||||
return new FakePojo("ignored");
|
||||
}
|
||||
|
||||
static Pojo anotherBeanTestOverride() {
|
||||
return new FakePojo("sub2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -17,155 +17,116 @@
|
|||
package org.springframework.test.context.bean.override.convention;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.engine.TestExecutionResult;
|
||||
import org.junit.platform.testkit.engine.EngineExecutionResults;
|
||||
import org.junit.platform.testkit.engine.EngineTestKit;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.aot.DisabledInAotMode;
|
||||
import org.springframework.test.context.junit.EngineTestKitUtils;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.THROWABLE;
|
||||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
|
||||
import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message;
|
||||
import static org.springframework.test.context.junit.EngineTestKitUtils.rootCause;
|
||||
|
||||
/**
|
||||
* {@link TestBean @TestBean} integration tests for failure scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see TestBeanIntegrationTests
|
||||
*/
|
||||
public class FailingTestBeanIntegrationTests {
|
||||
class FailingTestBeanIntegrationTests {
|
||||
|
||||
@Test
|
||||
void testBeanFailingNoFieldNameBean() {
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(NoOriginalBeanTestCase.class))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.cause()
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to override bean 'noOriginalBean'; " +
|
||||
"there is no bean definition to replace with that name of type java.lang.String"));
|
||||
Class<?> testClass = NoOriginalBeanTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
cause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to override bean 'noOriginalBean': there is no bean definition \
|
||||
to replace with that name of type java.lang.String"""))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeanFailingNoExplicitNameBean() {
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(BeanDefinitionToOverrideNotPresentTestCase.class))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.cause()
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to override bean 'notPresent'; " +
|
||||
"there is no bean definition to replace with that name of type java.lang.String"));
|
||||
Class<?> testClass = BeanDefinitionToOverrideNotPresentTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
cause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to override bean 'notPresent': there is no bean definition \
|
||||
to replace with that name of type java.lang.String"""))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeanFailingNoImplicitMethod() {
|
||||
Class<?> testClass = ExplicitTestOverrideMethodNotPresentTestCase.class;
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(testClass))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.rootCause().isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Failed to find a static test bean factory method in %s " +
|
||||
"with return type java.lang.String whose name matches one of the " +
|
||||
"supported candidates [notPresent]", testClass.getName()));
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
rootCause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Failed to find a static test bean factory method in %s with return type \
|
||||
java.lang.String whose name matches one of the supported candidates \
|
||||
[notPresent]""".formatted(testClass.getName())))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeanFailingNoExplicitMethod() {
|
||||
Class<?> testClass = ImplicitTestOverrideMethodNotPresentTestCase.class;
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(testClass))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.rootCause().isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Failed to find a static test bean factory method in %s " +
|
||||
"with return type java.lang.String whose name matches one of the " +
|
||||
"supported candidates [fieldTestOverride]", testClass.getName()));
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
rootCause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Failed to find a static test bean factory method in %s with return type \
|
||||
java.lang.String whose name matches one of the supported candidates \
|
||||
[fieldTestOverride]""".formatted(testClass.getName())))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeanFailingBeanOfWrongType() {
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(BeanTypeMismatchTestCase.class))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.rootCause().isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to override bean 'notString'; there is no bean definition to replace with " +
|
||||
"that name of type java.lang.String"));
|
||||
Class<?> testClass = BeanTypeMismatchTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
rootCause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to override bean 'notString': there is no bean definition to replace \
|
||||
with that name of type java.lang.String"""))));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean("field")
|
||||
String bean1() {
|
||||
return "prod";
|
||||
}
|
||||
|
||||
@Bean("nestedField")
|
||||
String bean2() {
|
||||
return "nestedProd";
|
||||
}
|
||||
|
||||
@Bean("methodRenamed1")
|
||||
String bean3() {
|
||||
return "Prod";
|
||||
}
|
||||
|
||||
@Bean("methodRenamed2")
|
||||
String bean4() {
|
||||
return "NestedProd";
|
||||
}
|
||||
}
|
||||
|
||||
@SpringJUnitConfig
|
||||
@DisabledInAotMode
|
||||
static class NoOriginalBeanTestCase {
|
||||
|
||||
@TestBean(name = "noOriginalBean")
|
||||
String noOriginalBean;
|
||||
|
||||
@Test
|
||||
void ignored() {
|
||||
void test() {
|
||||
fail("should fail earlier");
|
||||
}
|
||||
|
||||
static String noOriginalBeanTestOverride() {
|
||||
return "should be ignored";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringJUnitConfig
|
||||
@DisabledInAotMode
|
||||
static class BeanDefinitionToOverrideNotPresentTestCase {
|
||||
|
||||
@TestBean(name = "notPresent")
|
||||
String field;
|
||||
|
||||
@Test
|
||||
void ignored() {
|
||||
void test() {
|
||||
fail("should fail earlier");
|
||||
}
|
||||
|
||||
|
@ -175,40 +136,37 @@ public class FailingTestBeanIntegrationTests {
|
|||
}
|
||||
|
||||
@SpringJUnitConfig
|
||||
@DisabledInAotMode
|
||||
static class ExplicitTestOverrideMethodNotPresentTestCase {
|
||||
|
||||
@TestBean(methodName = "notPresent")
|
||||
String field;
|
||||
|
||||
@Test
|
||||
void ignored() {
|
||||
void test() {
|
||||
fail("should fail earlier");
|
||||
}
|
||||
}
|
||||
|
||||
@SpringJUnitConfig
|
||||
@DisabledInAotMode
|
||||
static class ImplicitTestOverrideMethodNotPresentTestCase {
|
||||
|
||||
@TestBean //expects fieldTestOverride method
|
||||
@TestBean // expects fieldTestOverride method
|
||||
String field;
|
||||
|
||||
@Test
|
||||
void ignored() {
|
||||
void test() {
|
||||
fail("should fail earlier");
|
||||
}
|
||||
}
|
||||
|
||||
@SpringJUnitConfig
|
||||
@DisabledInAotMode
|
||||
static class BeanTypeMismatchTestCase {
|
||||
|
||||
@TestBean(name = "notString")
|
||||
String field;
|
||||
|
||||
@Test
|
||||
void ignored() {
|
||||
void test() {
|
||||
fail("should fail earlier");
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
package org.springframework.test.context.bean.override.convention;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.engine.TestExecutionResult;
|
||||
import org.junit.platform.testkit.engine.EngineExecutionResults;
|
||||
import org.junit.platform.testkit.engine.EngineTestKit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
@ -31,11 +28,16 @@ import org.springframework.test.context.bean.override.example.RealExampleService
|
|||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.THROWABLE;
|
||||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
|
||||
|
||||
@SpringJUnitConfig(TestBeanByTypeIntegrationTests.ConfigByType.class)
|
||||
/**
|
||||
* {@link TestBean @TestBean} "by type" integration tests for success scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see FailingTestBeanByTypeIntegrationTests
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
public class TestBeanByTypeIntegrationTests {
|
||||
|
||||
@TestBean
|
||||
|
@ -61,6 +63,7 @@ public class TestBeanByTypeIntegrationTests {
|
|||
return new StringBuilder("CustomQualifier TestBean String");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByType(ApplicationContext ctx) {
|
||||
assertThat(this.anyNameForService)
|
||||
|
@ -85,42 +88,10 @@ public class TestBeanByTypeIntegrationTests {
|
|||
assertThat(ctx.getBean("one")).as("no qualifier needed").hasToString("Prod One");
|
||||
}
|
||||
|
||||
@Test
|
||||
void zeroCandidates() {
|
||||
Class<?> caseClass = CaseNone.class;
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(caseClass))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.cause()
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to select a bean definition to override, 0 bean definitions " +
|
||||
"found of type %s (as required by annotated field '%s.example')",
|
||||
ExampleService.class.getName(), caseClass.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tooManyCandidates() {
|
||||
Class<?> caseClass = CaseTooMany.class;
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(caseClass))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.cause()
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to select a bean definition to override, 2 bean definitions " +
|
||||
"found of type %s (as required by annotated field '%s.example')",
|
||||
ExampleService.class.getName(), caseClass.getSimpleName()));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ConfigByType {
|
||||
static class Config {
|
||||
|
||||
@Bean("example")
|
||||
ExampleService bean1() {
|
||||
return new RealExampleService("Production hello");
|
||||
|
@ -144,47 +115,4 @@ public class TestBeanByTypeIntegrationTests {
|
|||
}
|
||||
}
|
||||
|
||||
@SpringJUnitConfig(FailingNone.class)
|
||||
static class CaseNone {
|
||||
@TestBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {}
|
||||
|
||||
static ExampleService exampleTestOverride() {
|
||||
fail("unexpected override");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FailingNone {
|
||||
}
|
||||
|
||||
@SpringJUnitConfig(FailingTooMany.class)
|
||||
static class CaseTooMany {
|
||||
@TestBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {}
|
||||
|
||||
static ExampleService exampleTestOverride() {
|
||||
fail("unexpected override");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FailingTooMany {
|
||||
@Bean
|
||||
ExampleService bean1() {
|
||||
return new RealExampleService("1 Hello");
|
||||
}
|
||||
@Bean
|
||||
ExampleService bean2() {
|
||||
return new RealExampleService("2 Hello");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,30 +19,33 @@ package org.springframework.test.context.bean.override.convention;
|
|||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.engine.TestExecutionResult;
|
||||
import org.junit.platform.testkit.engine.EngineExecutionResults;
|
||||
import org.junit.platform.testkit.engine.EngineTestKit;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.THROWABLE;
|
||||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
|
||||
|
||||
/**
|
||||
* {@link TestBean @TestBean} inheritance integration tests for success scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see FailingTestBeanInheritanceIntegrationTests
|
||||
*/
|
||||
public class TestBeanInheritanceIntegrationTests {
|
||||
|
||||
static AbstractTestBeanIntegrationTestCase.Pojo nestedBeanOverride() {
|
||||
static AbstractTestBeanIntegrationTestCase.Pojo enclosingClassBeanOverride() {
|
||||
return new AbstractTestBeanIntegrationTestCase.FakePojo("in enclosing test class");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("Concrete inherited test with correct @TestBean setup")
|
||||
class ConcreteTestBeanIntegrationTests extends AbstractTestBeanIntegrationTestCase {
|
||||
public class ConcreteTestBeanIntegrationTests extends AbstractTestBeanIntegrationTestCase {
|
||||
|
||||
@TestBean(name = "pojo", methodName = "commonBeanOverride")
|
||||
Pojo pojo;
|
||||
|
||||
@TestBean(name = "pojo2", methodName = "nestedBeanOverride")
|
||||
@TestBean(name = "pojo2", methodName = "enclosingClassBeanOverride")
|
||||
Pojo pojo2;
|
||||
|
||||
static Pojo someBeanTestOverride() {
|
||||
|
@ -74,60 +77,4 @@ public class TestBeanInheritanceIntegrationTests {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void failsIfFieldInSupertypeButNoMethod() {
|
||||
Class<?> clazz = Failing1.class;
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(clazz))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.rootCause().isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("""
|
||||
Failed to find a static test bean factory method in %s with return type %s \
|
||||
whose name matches one of the supported candidates [someBeanTestOverride]""",
|
||||
clazz.getName(), AbstractTestBeanIntegrationTestCase.Pojo.class.getName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void failsIfMethod1InSupertypeAndMethod2InType() {
|
||||
Class<?> clazz = Failing2.class;
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(clazz))
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.rootCause().isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("""
|
||||
Found 2 competing static test bean factory methods in %s with return type %s \
|
||||
whose name matches one of the supported candidates \
|
||||
[thirdBeanTestOverride, anotherBeanTestOverride]""",
|
||||
clazz.getName(), AbstractTestBeanIntegrationTestCase.Pojo.class.getName()));
|
||||
}
|
||||
|
||||
static class Failing1 extends AbstractTestBeanIntegrationTestCase {
|
||||
|
||||
@Test
|
||||
void ignored() {
|
||||
}
|
||||
}
|
||||
|
||||
static class Failing2 extends AbstractTestBeanIntegrationTestCase {
|
||||
|
||||
static Pojo someBeanTestOverride() {
|
||||
return new FakePojo("ignored");
|
||||
}
|
||||
|
||||
static Pojo anotherBeanTestOverride() {
|
||||
return new FakePojo("sub2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ignored2() { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
/**
|
||||
* {@link TestBean @TestBean} integration tests for success scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see FailingTestBeanIntegrationTests
|
||||
*/
|
||||
|
@ -82,8 +84,8 @@ public class TestBeanIntegrationTests {
|
|||
|
||||
|
||||
@Nested
|
||||
@DisplayName("With @TestBean on enclosing class")
|
||||
class TestBeanNested {
|
||||
@DisplayName("With @TestBean in enclosing class")
|
||||
public class TestBeanNestedTests {
|
||||
|
||||
@Test
|
||||
void fieldHasOverride(ApplicationContext ctx) {
|
||||
|
@ -105,8 +107,8 @@ public class TestBeanIntegrationTests {
|
|||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("With factory method on enclosing class")
|
||||
class TestBeanNested2 {
|
||||
@DisplayName("With factory method in enclosing class")
|
||||
public class TestBeanNested2Tests {
|
||||
|
||||
@TestBean(methodName = "nestedFieldTestOverride", name = "nestedField")
|
||||
String nestedField2;
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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 org.junit.jupiter.api.Test;
|
||||
|
||||
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.example.RealExampleService;
|
||||
import org.springframework.test.context.junit.EngineTestKitUtils;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message;
|
||||
|
||||
/**
|
||||
* {@link MockitoBean @MockitoBean} "by type" integration tests for failure scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see MockitoBeanByTypeIntegrationTests
|
||||
*/
|
||||
class FailingMockitoBeanByTypeIntegrationTests {
|
||||
|
||||
@Test
|
||||
void zeroCandidates() {
|
||||
Class<?> testClass = ZeroCandidatesTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
cause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to select a bean definition to override: 0 bean definitions \
|
||||
found of type %s (as required by annotated field '%s.example')"""
|
||||
.formatted(ExampleService.class.getName(), testClass.getSimpleName())))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tooManyCandidates() {
|
||||
Class<?> testClass = TooManyCandidatesTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
cause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to select a bean definition to override: 2 bean definitions \
|
||||
found of type %s (as required by annotated field '%s.example')"""
|
||||
.formatted(ExampleService.class.getName(), testClass.getSimpleName())))));
|
||||
}
|
||||
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class ZeroCandidatesTestCase {
|
||||
|
||||
@MockitoBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
assertThat(example).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
}
|
||||
}
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class TooManyCandidatesTestCase {
|
||||
|
||||
@MockitoBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
assertThat(example).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
ExampleService bean1() {
|
||||
return new RealExampleService("1 Hello");
|
||||
}
|
||||
|
||||
@Bean
|
||||
ExampleService bean2() {
|
||||
return new RealExampleService("2 Hello");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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 org.junit.jupiter.api.Test;
|
||||
|
||||
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.example.RealExampleService;
|
||||
import org.springframework.test.context.junit.EngineTestKitUtils;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message;
|
||||
|
||||
/**
|
||||
* {@link MockitoSpyBean @MockitoSpyBean} "by type" integration tests for failure scenarios.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see MockitoSpyBeanByTypeIntegrationTests
|
||||
*/
|
||||
class FailingMockitoSpyBeanByTypeIntegrationTests {
|
||||
|
||||
@Test
|
||||
void zeroCandidates() {
|
||||
Class<?> testClass = ZeroCandidatesTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
cause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to select a bean to override by wrapping: 0 bean instances found of \
|
||||
type %s (as required by annotated field '%s.example')"""
|
||||
.formatted(ExampleService.class.getName(), testClass.getSimpleName())))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tooManyCandidates() {
|
||||
Class<?> testClass = TooManyCandidatesTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
cause(
|
||||
instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to select a bean to override by wrapping: 2 bean instances found of \
|
||||
type %s (as required by annotated field '%s.example')"""
|
||||
.formatted(ExampleService.class.getName(), testClass.getSimpleName())))));
|
||||
}
|
||||
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class ZeroCandidatesTestCase {
|
||||
|
||||
@MockitoSpyBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
assertThat(example).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
}
|
||||
}
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class TooManyCandidatesTestCase {
|
||||
|
||||
@MockitoSpyBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
assertThat(example).isNotNull();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
ExampleService bean1() {
|
||||
return new RealExampleService("1 Hello");
|
||||
}
|
||||
|
||||
@Bean
|
||||
ExampleService bean2() {
|
||||
return new RealExampleService("2 Hello");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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 org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.test.context.bean.override.example.ExampleService;
|
||||
import org.springframework.test.context.junit.EngineTestKitUtils;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf;
|
||||
import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message;
|
||||
|
||||
/**
|
||||
* {@link MockitoSpyBean @MockitoSpyBean} integration tests for failure scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see MockitoSpyBeanIntegrationTests
|
||||
*/
|
||||
class FailingMockitoSpyBeanIntegrationTests {
|
||||
|
||||
@Test
|
||||
void failWhenBeanNotPresentByType() {
|
||||
Class<?> testClass = BeanNotPresentByTypeTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
cause(instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to select a bean to override by wrapping: 0 bean instances found \
|
||||
of type %s (as required by annotated field '%s.notPresent')"""
|
||||
.formatted(ExampleService.class.getName(), testClass.getSimpleName())))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void failWhenBeanNotPresentByExplicitName() {
|
||||
Class<?> testClass = BeanNotPresentByExplicitNameTestCase.class;
|
||||
EngineTestKitUtils.executeTestsForClass(testClass).assertThatEvents().haveExactly(1,
|
||||
finishedWithFailure(
|
||||
cause(instanceOf(IllegalStateException.class),
|
||||
message("""
|
||||
Unable to override bean 'notPresentAtAll' by wrapping: \
|
||||
there is no existing bean instance with that name of type %s"""
|
||||
.formatted(ExampleService.class.getName())))));
|
||||
}
|
||||
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class BeanNotPresentByTypeTestCase {
|
||||
|
||||
@MockitoSpyBean
|
||||
ExampleService notPresent;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
}
|
||||
}
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class BeanNotPresentByExplicitNameTestCase {
|
||||
|
||||
@MockitoSpyBean(name = "notPresentAtAll")
|
||||
ExampleService field;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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 org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.test.context.bean.override.example.CustomQualifier;
|
||||
import org.springframework.test.context.bean.override.example.ExampleService;
|
||||
import org.springframework.test.context.bean.override.example.RealExampleService;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.BDDMockito.when;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* {@link MockitoBean @MockitoBean} "by type" integration tests for success scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see FailingMockitoBeanByTypeIntegrationTests
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
public class MockitoBeanByTypeIntegrationTests {
|
||||
|
||||
@MockitoBean
|
||||
ExampleService anyNameForService;
|
||||
|
||||
@MockitoBean
|
||||
@Qualifier("prefer")
|
||||
StringBuilder ambiguous;
|
||||
|
||||
@MockitoBean
|
||||
@CustomQualifier
|
||||
StringBuilder ambiguousMeta;
|
||||
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByType(ApplicationContext ctx) {
|
||||
assertThat(this.anyNameForService)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock()).as("isMock").isTrue())
|
||||
.isSameAs(ctx.getBean("example"))
|
||||
.isSameAs(ctx.getBean(ExampleService.class));
|
||||
|
||||
when(this.anyNameForService.greeting()).thenReturn("Mocked greeting");
|
||||
|
||||
assertThat(this.anyNameForService.greeting()).isEqualTo("Mocked greeting");
|
||||
verify(this.anyNameForService, times(1)).greeting();
|
||||
verifyNoMoreInteractions(this.anyNameForService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByTypeAndDisambiguatedByQualifier(ApplicationContext ctx) {
|
||||
assertThat(this.ambiguous)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock()).as("isMock").isTrue())
|
||||
.isSameAs(ctx.getBean("ambiguous2"));
|
||||
|
||||
assertThatException()
|
||||
.isThrownBy(() -> ctx.getBean(StringBuilder.class))
|
||||
.withMessageEndingWith("but found 2: ambiguous2,ambiguous1");
|
||||
|
||||
assertThat(this.ambiguous).isEmpty();
|
||||
assertThat(this.ambiguous.substring(0)).isNull();
|
||||
verify(this.ambiguous, times(1)).length();
|
||||
verify(this.ambiguous, times(1)).substring(anyInt());
|
||||
verifyNoMoreInteractions(this.ambiguous);
|
||||
}
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByTypeAndDisambiguatedByMetaQualifier(ApplicationContext ctx) {
|
||||
assertThat(this.ambiguousMeta)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock()).as("isMock").isTrue())
|
||||
.isSameAs(ctx.getBean("ambiguous1"));
|
||||
|
||||
assertThatException()
|
||||
.isThrownBy(() -> ctx.getBean(StringBuilder.class))
|
||||
.withMessageEndingWith("but found 2: ambiguous2,ambiguous1");
|
||||
|
||||
assertThat(this.ambiguousMeta).isEmpty();
|
||||
assertThat(this.ambiguousMeta.substring(0)).isNull();
|
||||
verify(this.ambiguousMeta, times(1)).length();
|
||||
verify(this.ambiguousMeta, times(1)).substring(anyInt());
|
||||
verifyNoMoreInteractions(this.ambiguousMeta);
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean("example")
|
||||
ExampleService bean1() {
|
||||
return new RealExampleService("Production hello");
|
||||
}
|
||||
|
||||
@Bean("ambiguous1")
|
||||
@Order(1)
|
||||
@CustomQualifier
|
||||
StringBuilder bean2() {
|
||||
return new StringBuilder("bean2");
|
||||
}
|
||||
|
||||
@Bean("ambiguous2")
|
||||
@Order(2)
|
||||
@Qualifier("prefer")
|
||||
StringBuilder bean3() {
|
||||
return new StringBuilder("bean3");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -51,12 +51,12 @@ public class MockitoBeanIntegrationTests {
|
|||
@MockitoBean(name = "nestedNonExistingBean")
|
||||
ExampleService nonExisting2;
|
||||
|
||||
|
||||
@Test
|
||||
void fieldHasOverride(ApplicationContext ctx) {
|
||||
assertThat(ctx.getBean("field"))
|
||||
.isInstanceOf(ExampleService.class)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock())
|
||||
.as("isMock").isTrue())
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock()).as("isMock").isTrue())
|
||||
.isSameAs(this.field);
|
||||
|
||||
assertThat(this.field.greeting()).as("mocked greeting").isNull();
|
||||
|
@ -66,8 +66,7 @@ public class MockitoBeanIntegrationTests {
|
|||
void renamedFieldHasOverride(ApplicationContext ctx) {
|
||||
assertThat(ctx.getBean("field"))
|
||||
.isInstanceOf(ExampleService.class)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock())
|
||||
.as("isMock").isTrue())
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock()).as("isMock").isTrue())
|
||||
.isSameAs(this.renamed1);
|
||||
|
||||
assertThat(this.renamed1.greeting()).as("mocked greeting").isNull();
|
||||
|
@ -77,23 +76,22 @@ public class MockitoBeanIntegrationTests {
|
|||
void fieldIsMockedWhenNoOriginalBean(ApplicationContext ctx) {
|
||||
assertThat(ctx.getBean("nonExistingBean"))
|
||||
.isInstanceOf(ExampleService.class)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock())
|
||||
.as("isMock").isTrue())
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock()).as("isMock").isTrue())
|
||||
.isSameAs(this.nonExisting1);
|
||||
|
||||
assertThat(this.nonExisting1.greeting()).as("mocked greeting").isNull();
|
||||
}
|
||||
|
||||
|
||||
@Nested
|
||||
@DisplayName("With @MockitoBean on enclosing class")
|
||||
class MockitoBeanNested {
|
||||
@DisplayName("With @MockitoBean in enclosing class")
|
||||
public class MockitoBeanNestedTests {
|
||||
|
||||
@Test
|
||||
void fieldHasOverride(ApplicationContext ctx) {
|
||||
assertThat(ctx.getBean("nestedField"))
|
||||
.isInstanceOf(ExampleService.class)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock())
|
||||
.as("isMock").isTrue())
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock()).as("isMock").isTrue())
|
||||
.isSameAs(MockitoBeanIntegrationTests.this.nestedField);
|
||||
}
|
||||
|
||||
|
@ -101,8 +99,7 @@ public class MockitoBeanIntegrationTests {
|
|||
void renamedFieldHasOverride(ApplicationContext ctx) {
|
||||
assertThat(ctx.getBean("nestedField"))
|
||||
.isInstanceOf(ExampleService.class)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock())
|
||||
.as("isMock").isTrue())
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock()).as("isMock").isTrue())
|
||||
.isSameAs(MockitoBeanIntegrationTests.this.renamed2);
|
||||
}
|
||||
|
||||
|
@ -110,8 +107,7 @@ public class MockitoBeanIntegrationTests {
|
|||
void fieldIsMockedWhenNoOriginalBean(ApplicationContext ctx) {
|
||||
assertThat(ctx.getBean("nestedNonExistingBean"))
|
||||
.isInstanceOf(ExampleService.class)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock())
|
||||
.as("isMock").isTrue())
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock()).as("isMock").isTrue())
|
||||
.isSameAs(MockitoBeanIntegrationTests.this.nonExisting2);
|
||||
}
|
||||
}
|
||||
|
@ -119,13 +115,16 @@ public class MockitoBeanIntegrationTests {
|
|||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean("field")
|
||||
ExampleService bean1() {
|
||||
return new RealExampleService("Hello Field");
|
||||
}
|
||||
|
||||
@Bean("nestedField")
|
||||
ExampleService bean2() {
|
||||
return new RealExampleService("Hello Nested Field");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,323 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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 org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.engine.TestExecutionResult;
|
||||
import org.junit.platform.testkit.engine.EngineExecutionResults;
|
||||
import org.junit.platform.testkit.engine.EngineTestKit;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.test.context.bean.override.example.CustomQualifier;
|
||||
import org.springframework.test.context.bean.override.example.ExampleService;
|
||||
import org.springframework.test.context.bean.override.example.RealExampleService;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.THROWABLE;
|
||||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.BDDMockito.when;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
public class MockitoByTypeIntegrationTests {
|
||||
|
||||
@Nested
|
||||
@SpringJUnitConfig(ConfigByType.class)
|
||||
class Mock {
|
||||
|
||||
@MockitoBean
|
||||
ExampleService anyNameForService;
|
||||
|
||||
@MockitoBean
|
||||
@Qualifier("prefer")
|
||||
StringBuilder ambiguous;
|
||||
|
||||
@MockitoBean
|
||||
@CustomQualifier
|
||||
StringBuilder ambiguousMeta;
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByType(ApplicationContext ctx) {
|
||||
assertThat(this.anyNameForService)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock())
|
||||
.as("isMock").isTrue())
|
||||
.isSameAs(ctx.getBean("example"))
|
||||
.isSameAs(ctx.getBean(ExampleService.class));
|
||||
|
||||
when(this.anyNameForService.greeting()).thenReturn("Mocked greeting");
|
||||
|
||||
assertThat(this.anyNameForService.greeting()).isEqualTo("Mocked greeting");
|
||||
verify(this.anyNameForService, times(1)).greeting();
|
||||
verifyNoMoreInteractions(this.anyNameForService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByTypeAndDisambiguatedByQualifier(ApplicationContext ctx) {
|
||||
assertThat(this.ambiguous)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock())
|
||||
.as("isMock").isTrue())
|
||||
.isSameAs(ctx.getBean("ambiguous2"));
|
||||
|
||||
assertThatException().isThrownBy(() -> ctx.getBean(StringBuilder.class))
|
||||
.withMessageEndingWith("but found 2: ambiguous2,ambiguous1");
|
||||
|
||||
assertThat(this.ambiguous.length()).isZero();
|
||||
assertThat(this.ambiguous.substring(0)).isNull();
|
||||
verify(this.ambiguous, times(1)).length();
|
||||
verify(this.ambiguous, times(1)).substring(anyInt());
|
||||
verifyNoMoreInteractions(this.ambiguous);
|
||||
}
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByTypeAndDisambiguatedByMetaQualifier(ApplicationContext ctx) {
|
||||
assertThat(this.ambiguousMeta)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isMock())
|
||||
.as("isMock").isTrue())
|
||||
.isSameAs(ctx.getBean("ambiguous1"));
|
||||
|
||||
assertThatException().isThrownBy(() -> ctx.getBean(StringBuilder.class))
|
||||
.withMessageEndingWith("but found 2: ambiguous2,ambiguous1");
|
||||
|
||||
assertThat(this.ambiguousMeta.length()).isZero();
|
||||
assertThat(this.ambiguousMeta.substring(0)).isNull();
|
||||
verify(this.ambiguousMeta, times(1)).length();
|
||||
verify(this.ambiguousMeta, times(1)).substring(anyInt());
|
||||
verifyNoMoreInteractions(this.ambiguousMeta);
|
||||
}
|
||||
|
||||
@Test
|
||||
void zeroCandidates() {
|
||||
Class<?> caseClass = CaseNone.class;
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(caseClass))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.cause()
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to select a bean definition to override, 0 bean definitions " +
|
||||
"found of type %s (as required by annotated field '%s.example')",
|
||||
ExampleService.class.getName(), caseClass.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tooManyCandidates() {
|
||||
Class<?> caseClass = CaseTooMany.class;
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(caseClass))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.cause()
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to select a bean definition to override, 2 bean definitions " +
|
||||
"found of type %s (as required by annotated field '%s.example')",
|
||||
ExampleService.class.getName(), caseClass.getSimpleName()));
|
||||
}
|
||||
|
||||
@SpringJUnitConfig(FailingNone.class)
|
||||
static class CaseNone {
|
||||
@MockitoBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
assertThat(example).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@SpringJUnitConfig(FailingTooMany.class)
|
||||
static class CaseTooMany {
|
||||
@MockitoBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
assertThat(example).isNotNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@SpringJUnitConfig(ConfigByType.class)
|
||||
class Spy {
|
||||
|
||||
@MockitoSpyBean
|
||||
ExampleService anyNameForService;
|
||||
|
||||
@MockitoSpyBean
|
||||
@Qualifier("prefer")
|
||||
StringBuilder ambiguous;
|
||||
|
||||
@MockitoSpyBean
|
||||
@CustomQualifier
|
||||
StringBuilder ambiguousMeta;
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByType(ApplicationContext ctx) {
|
||||
assertThat(this.anyNameForService)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy())
|
||||
.as("isSpy").isTrue())
|
||||
.isSameAs(ctx.getBean("example"))
|
||||
.isSameAs(ctx.getBean(ExampleService.class));
|
||||
|
||||
assertThat(this.anyNameForService.greeting()).isEqualTo("Production hello");
|
||||
verify(this.anyNameForService, times(1)).greeting();
|
||||
verifyNoMoreInteractions(this.anyNameForService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByTypeAndDisambiguatedByQualifier(ApplicationContext ctx) {
|
||||
assertThat(this.ambiguous)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy())
|
||||
.as("isSpy").isTrue())
|
||||
.isSameAs(ctx.getBean("ambiguous2"));
|
||||
|
||||
assertThatException().isThrownBy(() -> ctx.getBean(StringBuilder.class))
|
||||
.withMessageEndingWith("but found 2: ambiguous1,ambiguous2");
|
||||
|
||||
assertThat(this.ambiguous.toString()).isEqualTo("bean3");
|
||||
assertThat(this.ambiguous.length()).isEqualTo(5);
|
||||
verify(this.ambiguous, times(1)).length();
|
||||
verifyNoMoreInteractions(this.ambiguous); //mockito doesn't verify toString
|
||||
}
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByTypeAndDisambiguatedByMetaQualifier(ApplicationContext ctx) {
|
||||
assertThat(this.ambiguousMeta)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy())
|
||||
.as("isSpy").isTrue())
|
||||
.isSameAs(ctx.getBean("ambiguous1"));
|
||||
|
||||
assertThatException().isThrownBy(() -> ctx.getBean(StringBuilder.class))
|
||||
.withMessageEndingWith("but found 2: ambiguous1,ambiguous2");
|
||||
|
||||
assertThat(this.ambiguousMeta.toString()).isEqualTo("bean2");
|
||||
assertThat(this.ambiguousMeta.length()).isEqualTo(5);
|
||||
verify(this.ambiguousMeta, times(1)).length();
|
||||
verifyNoMoreInteractions(this.ambiguousMeta); //mockito doesn't verify toString
|
||||
}
|
||||
|
||||
@Test
|
||||
void zeroCandidates() {
|
||||
Class<?> caseClass = CaseNone.class;
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(caseClass))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.cause()
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to select a bean definition to override, 0 bean definitions " +
|
||||
"found of type %s (as required by annotated field '%s.example')",
|
||||
ExampleService.class.getName(), caseClass.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tooManyCandidates() {
|
||||
Class<?> caseClass = CaseTooMany.class;
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(caseClass))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.cause()
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to select a bean definition to override, 2 bean definitions " +
|
||||
"found of type %s (as required by annotated field '%s.example')",
|
||||
ExampleService.class.getName(), caseClass.getSimpleName()));
|
||||
}
|
||||
|
||||
@SpringJUnitConfig(FailingNone.class)
|
||||
static class CaseNone {
|
||||
@MockitoBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
assertThat(example).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@SpringJUnitConfig(FailingTooMany.class)
|
||||
static class CaseTooMany {
|
||||
@MockitoBean
|
||||
ExampleService example;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
assertThat(example).isNotNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ConfigByType {
|
||||
@Bean("example")
|
||||
ExampleService bean1() {
|
||||
return new RealExampleService("Production hello");
|
||||
}
|
||||
|
||||
@Bean("ambiguous1")
|
||||
@Order(1)
|
||||
@CustomQualifier
|
||||
StringBuilder bean2() {
|
||||
return new StringBuilder("bean2");
|
||||
}
|
||||
|
||||
@Bean("ambiguous2")
|
||||
@Order(2)
|
||||
@Qualifier("prefer")
|
||||
StringBuilder bean3() {
|
||||
return new StringBuilder("bean3");
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FailingNone {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class FailingTooMany {
|
||||
@Bean
|
||||
ExampleService bean1() {
|
||||
return new RealExampleService("1 Hello");
|
||||
}
|
||||
@Bean
|
||||
ExampleService bean2() {
|
||||
return new RealExampleService("2 Hello");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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 org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.test.context.bean.override.example.CustomQualifier;
|
||||
import org.springframework.test.context.bean.override.example.ExampleService;
|
||||
import org.springframework.test.context.bean.override.example.RealExampleService;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatException;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* {@link MockitoSpyBean @MockitoSpyBean} "by type" integration tests for success scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
* @see FailingMockitoSpyBeanByTypeIntegrationTests
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
public class MockitoSpyBeanByTypeIntegrationTests {
|
||||
|
||||
@MockitoSpyBean
|
||||
ExampleService anyNameForService;
|
||||
|
||||
@MockitoSpyBean
|
||||
@Qualifier("prefer")
|
||||
StringBuilder ambiguous;
|
||||
|
||||
@MockitoSpyBean
|
||||
@CustomQualifier
|
||||
StringBuilder ambiguousMeta;
|
||||
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByType(ApplicationContext ctx) {
|
||||
assertThat(this.anyNameForService)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy()).as("isSpy").isTrue())
|
||||
.isSameAs(ctx.getBean("example"))
|
||||
.isSameAs(ctx.getBean(ExampleService.class));
|
||||
|
||||
assertThat(this.anyNameForService.greeting()).isEqualTo("Production hello");
|
||||
verify(this.anyNameForService, times(1)).greeting();
|
||||
verifyNoMoreInteractions(this.anyNameForService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByTypeAndDisambiguatedByQualifier(ApplicationContext ctx) {
|
||||
assertThat(this.ambiguous)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy()).as("isSpy").isTrue())
|
||||
.isSameAs(ctx.getBean("ambiguous2"));
|
||||
|
||||
assertThatException()
|
||||
.isThrownBy(() -> ctx.getBean(StringBuilder.class))
|
||||
.withMessageEndingWith("but found 2: ambiguous1,ambiguous2");
|
||||
|
||||
assertThat(this.ambiguous.toString()).isEqualTo("bean3");
|
||||
assertThat(this.ambiguous.length()).isEqualTo(5);
|
||||
verify(this.ambiguous, times(1)).length();
|
||||
verifyNoMoreInteractions(this.ambiguous); //mockito doesn't verify toString
|
||||
}
|
||||
|
||||
@Test
|
||||
void overrideIsFoundByTypeAndDisambiguatedByMetaQualifier(ApplicationContext ctx) {
|
||||
assertThat(this.ambiguousMeta)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy()).as("isSpy").isTrue())
|
||||
.isSameAs(ctx.getBean("ambiguous1"));
|
||||
|
||||
assertThatException()
|
||||
.isThrownBy(() -> ctx.getBean(StringBuilder.class))
|
||||
.withMessageEndingWith("but found 2: ambiguous1,ambiguous2");
|
||||
|
||||
assertThat(this.ambiguousMeta.toString()).isEqualTo("bean2");
|
||||
assertThat(this.ambiguousMeta.length()).isEqualTo(5);
|
||||
verify(this.ambiguousMeta, times(1)).length();
|
||||
verifyNoMoreInteractions(this.ambiguousMeta); //mockito doesn't verify toString
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean("example")
|
||||
ExampleService bean1() {
|
||||
return new RealExampleService("Production hello");
|
||||
}
|
||||
|
||||
@Bean("ambiguous1")
|
||||
@Order(1)
|
||||
@CustomQualifier
|
||||
StringBuilder bean2() {
|
||||
return new StringBuilder("bean2");
|
||||
}
|
||||
|
||||
@Bean("ambiguous2")
|
||||
@Order(2)
|
||||
@Qualifier("prefer")
|
||||
StringBuilder bean3() {
|
||||
return new StringBuilder("bean3");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -19,9 +19,6 @@ package org.springframework.test.context.bean.override.mockito;
|
|||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.engine.TestExecutionResult;
|
||||
import org.junit.platform.testkit.engine.EngineExecutionResults;
|
||||
import org.junit.platform.testkit.engine.EngineTestKit;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
@ -29,9 +26,14 @@ import org.springframework.test.context.bean.override.example.ExampleService;
|
|||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.THROWABLE;
|
||||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
|
||||
|
||||
/**
|
||||
* {@link MockitoSpyBean @MockitoSpyBean} integration tests for success scenarios.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @since 6.2
|
||||
* @see FailingMockitoSpyBeanIntegrationTests
|
||||
*/
|
||||
@SpringJUnitConfig(MockitoBeanIntegrationTests.Config.class)
|
||||
public class MockitoSpyBeanIntegrationTests {
|
||||
|
||||
|
@ -47,73 +49,36 @@ public class MockitoSpyBeanIntegrationTests {
|
|||
@MockitoSpyBean(name = "nestedField")
|
||||
ExampleService renamed2;
|
||||
|
||||
|
||||
@Test
|
||||
void fieldHasOverride(ApplicationContext ctx) {
|
||||
assertThat(ctx.getBean("field"))
|
||||
.isInstanceOf(ExampleService.class)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy())
|
||||
.as("isSpy").isTrue())
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy()).as("isSpy").isTrue())
|
||||
.isSameAs(this.field);
|
||||
|
||||
assertThat(this.field.greeting()).as("spied greeting")
|
||||
.isEqualTo("Hello Field");
|
||||
assertThat(this.field.greeting()).as("spied greeting").isEqualTo("Hello Field");
|
||||
}
|
||||
|
||||
@Test
|
||||
void renamedFieldHasOverride(ApplicationContext ctx) {
|
||||
assertThat(ctx.getBean("field"))
|
||||
.isInstanceOf(ExampleService.class)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy())
|
||||
.as("isSpy").isTrue())
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy()).as("isSpy").isTrue())
|
||||
.isSameAs(this.renamed1);
|
||||
|
||||
assertThat(this.field.greeting()).as("spied greeting")
|
||||
.isEqualTo("Hello Field");
|
||||
}
|
||||
|
||||
@Test
|
||||
void failWhenBeanNotPresentByType() {
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(Failure1.class))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.cause()
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to select a bean to override by wrapping, " +
|
||||
"0 bean instances found of type %s " +
|
||||
"(as required by annotated field '%s.notPresent')",
|
||||
ExampleService.class.getName(), Failure1.class.getSimpleName()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void failWhenBeanNotPresentByExplicitName() {
|
||||
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter")//
|
||||
.selectors(selectClass(Failure2.class))//
|
||||
.execute();
|
||||
|
||||
assertThat(results.allEvents().failed().stream()).hasSize(1).first()
|
||||
.satisfies(e -> assertThat(e.getRequiredPayload(TestExecutionResult.class)
|
||||
.getThrowable()).get(THROWABLE)
|
||||
.cause()
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessage("Unable to override bean 'notPresentAtAll' by wrapping; " +
|
||||
"there is no existing bean instance with that name of type %s",
|
||||
ExampleService.class.getName()));
|
||||
assertThat(this.renamed1.greeting()).as("spied greeting").isEqualTo("Hello Field");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("With @MockitoSpyBean on enclosing class")
|
||||
class MockitoBeanNested {
|
||||
@DisplayName("With @MockitoSpyBean in enclosing class")
|
||||
public class MockitoSpyBeanNestedTests {
|
||||
|
||||
@Test
|
||||
void fieldHasOverride(ApplicationContext ctx) {
|
||||
assertThat(ctx.getBean("nestedField"))
|
||||
.isInstanceOf(ExampleService.class)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy())
|
||||
.as("isSpy").isTrue())
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy()).as("isSpy").isTrue())
|
||||
.isSameAs(MockitoSpyBeanIntegrationTests.this.nestedField);
|
||||
|
||||
assertThat(MockitoSpyBeanIntegrationTests.this.nestedField.greeting())
|
||||
|
@ -125,36 +90,13 @@ public class MockitoSpyBeanIntegrationTests {
|
|||
void renamedFieldHasOverride(ApplicationContext ctx) {
|
||||
assertThat(ctx.getBean("nestedField"))
|
||||
.isInstanceOf(ExampleService.class)
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy())
|
||||
.as("isSpy").isTrue())
|
||||
.satisfies(o -> assertThat(Mockito.mockingDetails(o).isSpy()).as("isSpy").isTrue())
|
||||
.isSameAs(MockitoSpyBeanIntegrationTests.this.renamed2);
|
||||
|
||||
|
||||
assertThat(MockitoSpyBeanIntegrationTests.this.renamed2.greeting())
|
||||
.as("spied greeting")
|
||||
.isEqualTo("Hello Nested Field");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class Failure1 {
|
||||
|
||||
@MockitoSpyBean
|
||||
ExampleService notPresent;
|
||||
|
||||
@Test
|
||||
void ignored() { }
|
||||
|
||||
}
|
||||
|
||||
@SpringJUnitConfig
|
||||
static class Failure2 {
|
||||
|
||||
@MockitoSpyBean(name = "notPresentAtAll")
|
||||
ExampleService field;
|
||||
|
||||
@Test
|
||||
void ignored() { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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.junit;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.junit.platform.testkit.engine.EngineTestKit;
|
||||
import org.junit.platform.testkit.engine.Events;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
|
||||
|
||||
/**
|
||||
* Utilities for tests that use JUnit's {@link EngineTestKit}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.2
|
||||
*/
|
||||
public class EngineTestKitUtils {
|
||||
|
||||
public static Events executeTestsForClass(Class<?> testClass) {
|
||||
return EngineTestKit.engine("junit-jupiter")
|
||||
.selectors(selectClass(testClass))
|
||||
.execute()
|
||||
.testEvents();
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("varargs")
|
||||
public static Condition<Throwable> rootCause(Condition<Throwable>... conditions) {
|
||||
List<Condition<Throwable>> list = Arrays.stream(conditions)
|
||||
.map(EngineTestKitUtils::rootCause)
|
||||
.collect(toList());
|
||||
|
||||
return Assertions.allOf(list);
|
||||
}
|
||||
|
||||
private static Condition<Throwable> rootCause(Condition<Throwable> condition) {
|
||||
return new Condition<>(throwable -> condition.matches(getRootCause(throwable)),
|
||||
"throwable root cause matches %s", condition);
|
||||
}
|
||||
|
||||
private static Throwable getRootCause(Throwable throwable) {
|
||||
Throwable cause = throwable.getCause();
|
||||
if (cause == null) {
|
||||
return throwable;
|
||||
}
|
||||
return getRootCause(cause);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue