Ensure Bean Overrides are discovered once in @Nested hierarchies
Changes made to the Bean Override search algorithms in commit
9181cce65f resulted in a regression that caused tests to start failing
due to duplicate BeanOverrideHandlers under the following circumstances.
- An enclosing class (typically a top-level test class) declares a
@BeanOverride such as @MockitoBean.
- An inner class is declared in that enclosing class.
- A @Nested test class which extends that inner class is declared in
the same enclosing class.
The reason for the duplicate detection is that the current search
algorithm visits the common enclosing class twice.
To address that, this commit revises the search algorithm in
BeanOverrideHandler so that enclosing classes are only visited once.
See gh-33925
Closes gh-34324
This commit is contained in:
@@ -132,7 +132,7 @@ public abstract class BeanOverrideHandler {
|
||||
|
||||
private static List<BeanOverrideHandler> findHandlers(Class<?> testClass, boolean localFieldsOnly) {
|
||||
List<BeanOverrideHandler> handlers = new ArrayList<>();
|
||||
findHandlers(testClass, testClass, handlers, localFieldsOnly);
|
||||
findHandlers(testClass, testClass, handlers, localFieldsOnly, new HashSet<>());
|
||||
return handlers;
|
||||
}
|
||||
|
||||
@@ -146,26 +146,30 @@ public abstract class BeanOverrideHandler {
|
||||
* @param testClass the original test class
|
||||
* @param handlers the list of handlers found
|
||||
* @param localFieldsOnly whether to search only on local fields within the type hierarchy
|
||||
* @param visitedEnclosingClasses the set of enclosing classes already visited
|
||||
* @since 6.2.2
|
||||
*/
|
||||
private static void findHandlers(Class<?> clazz, Class<?> testClass, List<BeanOverrideHandler> handlers,
|
||||
boolean localFieldsOnly) {
|
||||
boolean localFieldsOnly, Set<Class<?>> visitedEnclosingClasses) {
|
||||
|
||||
// 1) Search enclosing class hierarchy.
|
||||
if (!localFieldsOnly && TestContextAnnotationUtils.searchEnclosingClass(clazz)) {
|
||||
findHandlers(clazz.getEnclosingClass(), testClass, handlers, localFieldsOnly);
|
||||
Class<?> enclosingClass = clazz.getEnclosingClass();
|
||||
if (visitedEnclosingClasses.add(enclosingClass)) {
|
||||
findHandlers(enclosingClass, testClass, handlers, localFieldsOnly, visitedEnclosingClasses);
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Search class hierarchy.
|
||||
Class<?> superclass = clazz.getSuperclass();
|
||||
if (superclass != null && superclass != Object.class) {
|
||||
findHandlers(superclass, testClass, handlers, localFieldsOnly);
|
||||
findHandlers(superclass, testClass, handlers, localFieldsOnly, visitedEnclosingClasses);
|
||||
}
|
||||
|
||||
if (!localFieldsOnly) {
|
||||
// 3) Search interfaces.
|
||||
for (Class<?> ifc : clazz.getInterfaces()) {
|
||||
findHandlers(ifc, testClass, handlers, localFieldsOnly);
|
||||
findHandlers(ifc, testClass, handlers, localFieldsOnly, visitedEnclosingClasses);
|
||||
}
|
||||
|
||||
// 4) Process current class.
|
||||
|
||||
Reference in New Issue
Block a user