Skip to content

Commit bf120cf

Browse files
lukasdoodrotbohm
authored andcommitted
GH-466 - Allow using ApplicationModuleTest outside of module packages.
1 parent 69499b9 commit bf120cf

File tree

3 files changed

+69
-3
lines changed

3 files changed

+69
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2022-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package otherpackage.integration;
17+
18+
import example.order.Order;
19+
import example.order.OrderManagement;
20+
import lombok.RequiredArgsConstructor;
21+
import org.junit.jupiter.api.Test;
22+
import org.springframework.modulith.test.ApplicationModuleTest;
23+
24+
/**
25+
* Test to showcase {@link ApplicationModuleTest} outside of a module package
26+
*/
27+
@ApplicationModuleTest(module = "order", classes = {example.Application.class})
28+
@RequiredArgsConstructor
29+
class OrderIntegrationTests {
30+
31+
private final OrderManagement orders;
32+
33+
@Test
34+
void completesOrder() {
35+
orders.complete(new Order());
36+
}
37+
}

spring-modulith-test/src/main/java/org/springframework/modulith/test/ApplicationModuleTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@
7676
*/
7777
String[] extraIncludes() default {};
7878

79+
/**
80+
* Logical name of the module in case {@link ApplicationModuleTest} will be used outside a module package
81+
*/
82+
String module() default "";
83+
84+
@AliasFor(annotation = SpringBootTest.class)
85+
Class<?>[] classes() default {};
86+
7987
/**
8088
* The type of web environment to create when applicable. Defaults to {@link WebEnvironment#MOCK}.
8189
*

spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleTestExecution.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.modulith.core.ApplicationModules;
3535
import org.springframework.modulith.core.JavaPackage;
3636
import org.springframework.modulith.test.ApplicationModuleTest.BootstrapMode;
37+
import org.springframework.util.StringUtils;
3738
import org.springframework.util.function.SingletonSupplier;
3839

3940
/**
@@ -94,12 +95,21 @@ public static Supplier<ModuleTestExecution> of(Class<?> type) {
9495

9596
var annotation = AnnotatedElementUtils.findMergedAnnotation(type, ApplicationModuleTest.class);
9697
var packageName = type.getPackage().getName();
98+
var optionalModulithType = findSpringBootApplicationByClasses(annotation);
9799

98-
var modulithType = MODULITH_TYPES.computeIfAbsent(type,
99-
it -> new AnnotatedClassFinder(SpringBootApplication.class).findFromPackage(packageName));
100+
var modulithType = optionalModulithType.orElseGet(() -> MODULITH_TYPES.computeIfAbsent(type,
101+
it -> new AnnotatedClassFinder(SpringBootApplication.class).findFromPackage(packageName)));
100102
var modules = ApplicationModules.of(modulithType);
101-
var module = modules.getModuleForPackage(packageName).orElseThrow( //
103+
104+
var moduleName = annotation.module();
105+
ApplicationModule module;
106+
if (StringUtils.hasText(moduleName)) {
107+
module = modules.getModuleByName(moduleName).orElseThrow( //
108+
() -> new IllegalStateException(String.format("Unable to find module %s!", moduleName)));
109+
} else {
110+
module = modules.getModuleForPackage(packageName).orElseThrow( //
102111
() -> new IllegalStateException(String.format("Package %s is not part of any module!", packageName)));
112+
}
103113

104114
return EXECUTIONS.computeIfAbsent(new Key(module.getBasePackage().getName(), annotation),
105115
it -> new ModuleTestExecution(annotation, modules, module));
@@ -230,5 +240,16 @@ private static Stream<ApplicationModule> getExtraModules(ApplicationModuleTest a
230240
.flatMap(Optional::stream);
231241
}
232242

243+
private static Optional<Class<?>> findSpringBootApplicationByClasses(ApplicationModuleTest annotation) {
244+
for (Class<?> clazz : annotation.classes()) {
245+
Class<?> modulithType = MODULITH_TYPES.computeIfAbsent(clazz,
246+
it -> new AnnotatedClassFinder(SpringBootApplication.class).findFromPackage(clazz.getPackageName()));
247+
if (modulithType != null) {
248+
return Optional.of(modulithType);
249+
}
250+
}
251+
return Optional.empty();
252+
}
253+
233254
private static record Key(String moduleBasePackage, ApplicationModuleTest annotation) {}
234255
}

0 commit comments

Comments
 (0)