Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application module test Includes unwanted beans in test run #320

Closed
danstooamerican opened this issue Oct 12, 2023 · 10 comments
Closed

Application module test Includes unwanted beans in test run #320

danstooamerican opened this issue Oct 12, 2023 · 10 comments
Assignees
Labels
in: test support Spring Boot integration testing type: improvement Minor improvements
Milestone

Comments

@danstooamerican
Copy link

danstooamerican commented Oct 12, 2023

We have encountered an issue with the annotation @ApplicationModuleTest, where the test appears to require more beans (from other modules) than expected. The module under test only depends on the Core module which is correctly picked up in the logs. Please see the stack trace and code snippets below for more details.

We use version 1.1.0-SNAPSHOT.

Modulith config from main Application java file

@Modulith(
        systemName = "MySystem",
        sharedModules = { "my.application.core" },
        useFullyQualifiedModuleNames = true
)

Test

//src/test/java/my/application/my-module/MyIntegrationTest.java
@ApplicationModuleTest
class MyIntegrationTest {
    @Autowired
    SomeBean someBean;

    @Test
    void my_test(){
        ...
    }
}

Stacktrace:

java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@6aeffa57 testClass = my.application.my-module.MyIntegrationTest, locations = [], classes = [my.application.name.Application], contextInitializerClasses = [], activeProfiles = [], propertySourceLocations = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [[ImportsContextCustomizer@22cd5706 key = [...]

	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:143)
	at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:127)
	at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:191)
	at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:130)
	at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:241)
	at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$10(ClassBasedTestDescriptor.java:377)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:382)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$11(ClassBasedTestDescriptor.java:377)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310)
	at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:376)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$6(ClassBasedTestDescriptor.java:289)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:288)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:278)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:277)
	at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$before$2(ClassBasedTestDescriptor.java:203)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:202)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:84)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:148)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ControllerBeanFromAnotherModule' defined in file [/home/user/git/target/classes/my/application/anotherModule/ControllerBeanFromAnotherModule.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'serviceFromAnotherModule' defined in file [/home/user/git/target/classes/my/application/anotherModule/BeanFromAnotherModule.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'my.application.anotherModule.BeanFromAnotherModuleSettings' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:245)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1352)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1189)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:942)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
	at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137)
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58)
	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46)
	at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1406)
	at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:545)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137)
	at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:187)
	at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:119)
	... 65 more
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'serviceFromAnotherModule' defined in file [/home/user/git/target/classes/my/application/anotherModule/BeanFromAnotherModule.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'my.application.anotherModule.BeanFromAnotherModuleSettings' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:245)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1352)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1189)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1417)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:888)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
	... 89 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'my.application.anotherModule.BeanFromAnotherModuleSettings' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1824)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1383)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:888)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
	... 103 more

Modulith Test logs

16:12:49.892 [main] INFO  c.tngtech.archunit.core.PluginLoader - Detected Java version 18.0.2-ea
16:13:02.701 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - Bootstrapping @org.springframework.modulith.test.ApplicationModuleTest for Module in mode STANDALONE (class my.application.name.Application)…
16:13:02.701 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - 
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - # Module
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > Logical name: my.application.my-module
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > Base package: my.application.my-module
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > Named interfaces:
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + NamedInterface: name=... , types=[ ... ]
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + NamedInterface: name=..., types=[ ... ]
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > Direct module dependencies: my.application.core
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > Spring beans:
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + …....
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + …....
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + …....
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …...
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …...
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …...
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …...
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …...
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - 
16:13:02.723 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - Shared modules:
16:13:02.724 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > my.application.core
16:13:02.724 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - 
16:13:02.724 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - Included dependencies:
16:13:02.748 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - 
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - # Core
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > Logical name: my.application.core
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > Base package: my.application.core
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > Named interfaces:
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + NamedInterface: name=<<UNNAMED>>, types=[ ... ]
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + NamedInterface: name=..., types=[ ... ]
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + NamedInterface: name=..., types=[ ... ]
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + NamedInterface: name=..., types=[ ... ]
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + NamedInterface: name=...-converter, types=[ ... ]
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > Direct module dependencies: none
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - > Spring beans:
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + …....
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + …....
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   + …....
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.749 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o …....
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o java.time.Clock
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o java.util.concurrent.Executor
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o javax.sql.DataSource
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o org.hibernate.context.spi.CurrentTenantIdentifierResolver
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o org.springframework.orm.jpa.JpaTransactionManager
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o org.springframework.orm.jpa.JpaVendorAdapter
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o org.springframework.security.web.SecurityFilterChain
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o org.springframework.transaction.support.TransactionTemplate
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer -   o org.springframework.web.reactive.function.client.WebClient
16:13:02.750 [main] INFO  o.s.m.t.ModuleContextCustomizerFactory$ModuleContextCustomizer - 
@danstooamerican
Copy link
Author

As in #319 we have modules that start with the same string. However, our issue persists if we rename the module packages. Deleting the wrongly included module only leads to other wrong modules being included in the test slice.

@odrotbohm
Copy link
Member

Can you share the package structure of your application?

@odrotbohm odrotbohm self-assigned this Oct 13, 2023
@odrotbohm odrotbohm added the meta: waiting for feedback Waiting for feedback of the original reporter label Oct 13, 2023
@danstooamerican
Copy link
Author

danstooamerican commented Oct 13, 2023

We have a very simple package structure. Every module is structured in the same way (controllers, application, domain, infrastructure). The top-level package of a module may contain classes that are accessed by other modules. We define a package-info.java in the top-level package to specify @ApplicationModule. From what we can tell it is not isolated to one module that is wrongly included but affects all. It also doesn't matter which module is under test.

Our tests are organized in the same package structure. Integration tests are defined in the top-level package of a module.

de.mycompany.product
| - module1
  | - controllers
  | - application
  | - domain
  | - infrastructure
| - module2
| - module
| - ...

@odrotbohm
Copy link
Member

Is there any Spring configuration within core or the root application package, that might manually trigger the inclusion of beans located in other parts of the code base?

@danstooamerican
Copy link
Author

danstooamerican commented Oct 13, 2023

I identified the commit that broke our tests. The only thing I changed in core was to include a new module package in @ComponentScan and @EnableJpaRepositories. We previously did the same thing with other modules without any issues. The name of the module is notifications.

The newly created module contains a couple configuration classes that define beans which are only used inside the module. The module had no dependencies on other modules at the time.

@danstooamerican
Copy link
Author

Ok, I removed the added configuration in core which resolved the issue. This seems very odd to me and doesn't explain why it works with the other modules.

@odrotbohm
Copy link
Member

We currently only reconfigure the autoconfiguration which is considered by the component scanning automatically set up by Spring Boot. Every other, manual configuration that triggers a dedicated component scanning (e.g., @EnableJpaRepositories) is currently not interfered with.

I have a prototypical fix for this that deploys a BeanDefinitionRegistryPostProcessor to explicitly drop beans that are located in modules not currently bootstrapped, which should basically result in the behavior you expect. This might also be a cure for #316.

How quickly would you be able to try a 1.1 snapshot?

odrotbohm added a commit that referenced this issue Oct 13, 2023
We now explicitly drop all beans resulting in a type that's contained in an application module *not* included in the current test bootstrap.
@odrotbohm odrotbohm changed the title ApplicationModuleTest Includes Unwanted Beans in Test Application module test Includes unwanted beans in test run Oct 13, 2023
@odrotbohm odrotbohm added the type: improvement Minor improvements label Oct 13, 2023
@odrotbohm odrotbohm added this to the 1.1 RC1 milestone Oct 13, 2023
@danstooamerican
Copy link
Author

danstooamerican commented Oct 13, 2023

We currently only reconfigure the autoconfiguration which is considered by the component scanning automatically set up by Spring Boot. Every other, manual configuration that triggers a dedicated component scanning (e.g., @EnableJpaRepositories) is currently not interfered with.

I have a prototypical fix for this that deploys a BeanDefinitionRegistryPostProcessor to explicitly drop beans that are located in modules not currently bootstrapped, which should basically result in the behavior you expect. This might also be a cure for #316.

How quickly would you be able to try a 1.1 snapshot?

Tonight :)

We are using spring-modulith-starter-jpa.

@odrotbohm
Copy link
Member

odrotbohm commented Oct 13, 2023

Fix is in, snapshots should be available. Enabling trace logging should output the bean names that are dropped through that particular mechanism.

@danstooamerican
Copy link
Author

Your fix works as expected. Our tests run without problems now ;)
I hope this isn't just a quick fix and is sustainable. Thank you @odrotbohm for your fast solution.

@odrotbohm odrotbohm added in: test support Spring Boot integration testing and removed meta: waiting for feedback Waiting for feedback of the original reporter labels Oct 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test support Spring Boot integration testing type: improvement Minor improvements
Projects
None yet
Development

No branches or pull requests

2 participants