GH-466 - Allow using ApplicationModuleTest outside of module packages.

This commit is contained in:
Lukas Dohmen
2024-05-22 17:37:43 +02:00
committed by Oliver Drotbohm
parent 69499b9258
commit bf120cf44b
3 changed files with 69 additions and 3 deletions

View File

@@ -76,6 +76,14 @@ public @interface ApplicationModuleTest {
*/
String[] extraIncludes() default {};
/**
* Logical name of the module in case {@link ApplicationModuleTest} will be used outside a module package
*/
String module() default "";
@AliasFor(annotation = SpringBootTest.class)
Class<?>[] classes() default {};
/**
* The type of web environment to create when applicable. Defaults to {@link WebEnvironment#MOCK}.
*

View File

@@ -34,6 +34,7 @@ import org.springframework.modulith.core.ApplicationModule;
import org.springframework.modulith.core.ApplicationModules;
import org.springframework.modulith.core.JavaPackage;
import org.springframework.modulith.test.ApplicationModuleTest.BootstrapMode;
import org.springframework.util.StringUtils;
import org.springframework.util.function.SingletonSupplier;
/**
@@ -94,12 +95,21 @@ public class ModuleTestExecution implements Iterable<ApplicationModule> {
var annotation = AnnotatedElementUtils.findMergedAnnotation(type, ApplicationModuleTest.class);
var packageName = type.getPackage().getName();
var optionalModulithType = findSpringBootApplicationByClasses(annotation);
var modulithType = MODULITH_TYPES.computeIfAbsent(type,
it -> new AnnotatedClassFinder(SpringBootApplication.class).findFromPackage(packageName));
var modulithType = optionalModulithType.orElseGet(() -> MODULITH_TYPES.computeIfAbsent(type,
it -> new AnnotatedClassFinder(SpringBootApplication.class).findFromPackage(packageName)));
var modules = ApplicationModules.of(modulithType);
var module = modules.getModuleForPackage(packageName).orElseThrow( //
var moduleName = annotation.module();
ApplicationModule module;
if (StringUtils.hasText(moduleName)) {
module = modules.getModuleByName(moduleName).orElseThrow( //
() -> new IllegalStateException(String.format("Unable to find module %s!", moduleName)));
} else {
module = modules.getModuleForPackage(packageName).orElseThrow( //
() -> new IllegalStateException(String.format("Package %s is not part of any module!", packageName)));
}
return EXECUTIONS.computeIfAbsent(new Key(module.getBasePackage().getName(), annotation),
it -> new ModuleTestExecution(annotation, modules, module));
@@ -230,5 +240,16 @@ public class ModuleTestExecution implements Iterable<ApplicationModule> {
.flatMap(Optional::stream);
}
private static Optional<Class<?>> findSpringBootApplicationByClasses(ApplicationModuleTest annotation) {
for (Class<?> clazz : annotation.classes()) {
Class<?> modulithType = MODULITH_TYPES.computeIfAbsent(clazz,
it -> new AnnotatedClassFinder(SpringBootApplication.class).findFromPackage(clazz.getPackageName()));
if (modulithType != null) {
return Optional.of(modulithType);
}
}
return Optional.empty();
}
private static record Key(String moduleBasePackage, ApplicationModuleTest annotation) {}
}