You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While working on #33925 and #34194, I noticed inconsistencies and peculiarities in the search algorithm for @TestBean factory methods.
Specifically, for a @TestBean field defined in a top-level class, the search for a factory method begins with the current test class (which may be a subclass of or or a @Nested class defined in the class in which the @TestBean field is declared). Whereas, for a @TestBean field defined in a @Nested test class, the search for a factory method begins with the @Nested test class.
The above leads to inconsistent factory method discovery for @TestBean factory methods.
In addition, the algorithm used for top-level classes results in "duplicate bean override" failures for cases which are clearly not duplicates but rather an "override of an override". In other words, a @TestBean declaration in a subclass (which resolves to a factory method in the subclass) currently cannot override a seemingly identical @TestBean declaration in a superclass (which resolves to a factory method in the superclass), which some might consider a bug.
Example
@SpringJUnitConfigclassBaseTests {
@TestBeanStringenigma;
staticStringenigma() {
return"enigma in superclass";
}
@Testvoidtest() {
assertThat(enigma).isEqualTo("enigma in superclass");
}
@NestedclassNestedTests {
@TestBeanStringenigma;
staticStringenigma() {
return"enigma in nested class";
}
@Testvoidtest() {
assertThat(enigma).isEqualTo("enigma in nested class");
}
}
@ConfigurationstaticclassConfig {
@BeanStringenigma() {
return"enigma in @Configuration class";
}
}
}
classExtendedTestsextendsBaseTests {
@TestBeanStringenigma;
staticStringenigma() {
return"enigma in subclass";
}
@Test@Overridevoidtest() {
assertThat(enigma).isEqualTo("enigma in subclass");
}
}
BaseTests passes as expected.
BaseTests.NestedTests currently passes because of the aforementioned inconsistent search algorithm.
ExtendedTests fails with the following error.
java.lang.IllegalStateException: Duplicate BeanOverrideHandler discovered in test class example.ExtendedTests: [TestBeanOverrideHandler@2dc3271b field = java.lang.String example.ExtendedTests.enigma, beanType = java.lang.String, beanName = [null], strategy = REPLACE_OR_CREATE, factoryMethod = enigma@ExtendedTests]
The cause of the exception is due to the fact that two @TestBean override handlers resolve the same factory method enigma@ExtendedTests; however, one might expect those to resolve to enigma@BaseTests and enigma@ExtendedTests (i.e., two distinct factory methods).
Proposal
Resolve @TestBean factory methods consistently, beginning the search with the declaring class of the @TestBean field.
One downside to the proposal is that @TestBean factory methods would no longer be able to be resolved lazily in subclasses (somewhat like "late binding" to a concrete method), which would be a change in behavior.
Another option is to make the factory method search algorithm for @Nested test classes align with the current semantics for top-level test classes.
sbrannen
changed the title
@TestBean factory method resolution is inconsistent@TestBean factory method resolution is incorrect within class hierarchy
Jan 7, 2025
Overview
While working on #33925 and #34194, I noticed inconsistencies and peculiarities in the search algorithm for
@TestBean
factory methods.Specifically, for a
@TestBean
field defined in a top-level class, the search for a factory method begins with the current test class (which may be a subclass of or or a@Nested
class defined in the class in which the@TestBean
field is declared). Whereas, for a@TestBean
field defined in a@Nested
test class, the search for a factory method begins with the@Nested
test class.The above leads to inconsistent factory method discovery for
@TestBean
factory methods.In addition, the algorithm used for top-level classes results in "duplicate bean override" failures for cases which are clearly not duplicates but rather an "override of an override". In other words, a
@TestBean
declaration in a subclass (which resolves to a factory method in the subclass) currently cannot override a seemingly identical@TestBean
declaration in a superclass (which resolves to a factory method in the superclass), which some might consider a bug.Example
BaseTests
passes as expected.BaseTests.NestedTests
currently passes because of the aforementioned inconsistent search algorithm.ExtendedTests
fails with the following error.The cause of the exception is due to the fact that two
@TestBean
override handlers resolve the same factory methodenigma@ExtendedTests
; however, one might expect those to resolve toenigma@BaseTests
andenigma@ExtendedTests
(i.e., two distinct factory methods).Proposal
@TestBean
factory methods consistently, beginning the search with the declaring class of the@TestBean
field.One downside to the proposal is that
@TestBean
factory methods would no longer be able to be resolved lazily in subclasses (somewhat like "late binding" to a concrete method), which would be a change in behavior.Another option is to make the factory method search algorithm for
@Nested
test classes align with the current semantics for top-level test classes.Related Issues
@MockitoBean
at the type level on test classes #33925The text was updated successfully, but these errors were encountered: