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

@@ -0,0 +1,37 @@
/*
* Copyright 2022-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 otherpackage.integration;
import example.order.Order;
import example.order.OrderManagement;
import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.Test;
import org.springframework.modulith.test.ApplicationModuleTest;
/**
* Test to showcase {@link ApplicationModuleTest} outside of a module package
*/
@ApplicationModuleTest(module = "order", classes = {example.Application.class})
@RequiredArgsConstructor
class OrderIntegrationTests {
private final OrderManagement orders;
@Test
void completesOrder() {
orders.complete(new Order());
}
}

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) {}
}