diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java index 8ae3c3f0..ec331dc8 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/ModuleContextCustomizerFactory.java @@ -84,7 +84,7 @@ class ModuleContextCustomizerFactory implements ContextCustomizerFactory { beanFactory.registerSingleton(ModuleTestExecutionBeanDefinitionSelector.class.getName(), new ModuleTestExecutionBeanDefinitionSelector(testExecution)); - var events = new DefaultPublishedEvents(); + var events = PublishedEventsFactory.createPublishedEvents(); beanFactory.registerSingleton(events.getClass().getName(), events); context.addApplicationListener(events); } diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsFactory.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsFactory.java new file mode 100644 index 00000000..6094eb62 --- /dev/null +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright 2025 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 org.springframework.modulith.test; + +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.util.ClassUtils; + +/** + * Creates an instance of {@link PublishedEvents} or {@link AssertablePublishedEvents} depending on whether AssertJ is + * on the classpath or not. + * + * @author Oliver Drotbohm + * @since 1.4 + */ +class PublishedEventsFactory { + + private static final boolean ASSERT_J_PRESENT = ClassUtils.isPresent("org.assertj.core.api.Assert", + PublishedEventsParameterResolver.class.getClassLoader()); + + /** + * Returns whether AssertJ is present or not. + */ + static boolean isAssertJPresent() { + return ASSERT_J_PRESENT; + } + + /** + * Creates a instance of {@link PublishedEvents} that's also an {@link ApplicationListener} for + * {@link ApplicationEvent}s. + * + * @return will never be {@literal null}. + */ + @SuppressWarnings("unchecked") + static > T createPublishedEvents() { + return (T) (isAssertJPresent() ? new DefaultAssertablePublishedEvents() : new DefaultPublishedEvents()); + } +} diff --git a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java index 639a2d82..a7c964bc 100644 --- a/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java +++ b/spring-modulith-test/src/main/java/org/springframework/modulith/test/PublishedEventsParameterResolver.java @@ -27,7 +27,6 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; /** * Provides instances of {@link PublishedEvents} as test method parameters. @@ -36,9 +35,6 @@ import org.springframework.util.ClassUtils; */ class PublishedEventsParameterResolver implements ParameterResolver, AfterEachCallback { - private static final boolean ASSERT_J_PRESENT = ClassUtils.isPresent("org.assertj.core.api.Assert", - PublishedEventsParameterResolver.class.getClassLoader()); - private ThreadBoundApplicationListenerAdapter listener; private final Function lookup; @@ -59,7 +55,8 @@ class PublishedEventsParameterResolver implements ParameterResolver, AfterEachCa var type = parameterContext.getParameter().getType(); - if (type.getName().equals("org.springframework.modulith.test.AssertablePublishedEvents") && !ASSERT_J_PRESENT) { + if (type.getName().equals("org.springframework.modulith.test.AssertablePublishedEvents") + && !PublishedEventsFactory.isAssertJPresent()) { throw new IllegalStateException( "Method declares AssertablePublishedEvents as parameter but AssertJ is not on the classpath!"); } @@ -74,9 +71,7 @@ class PublishedEventsParameterResolver implements ParameterResolver, AfterEachCa @Override public PublishedEvents resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - var publishedEvents = ASSERT_J_PRESENT - ? new DefaultAssertablePublishedEvents() - : new DefaultPublishedEvents(); + var publishedEvents = PublishedEventsFactory.createPublishedEvents(); initializeListener(extensionContext); listener.registerDelegate(publishedEvents); diff --git a/spring-modulith-test/src/test/java/org/springframework/modulith/test/ModuleContextCustomizerUnitTests.java b/spring-modulith-test/src/test/java/org/springframework/modulith/test/ModuleContextCustomizerUnitTests.java index 58fbd8fc..9996394c 100644 --- a/spring-modulith-test/src/test/java/org/springframework/modulith/test/ModuleContextCustomizerUnitTests.java +++ b/spring-modulith-test/src/test/java/org/springframework/modulith/test/ModuleContextCustomizerUnitTests.java @@ -21,9 +21,12 @@ import example.module.SampleTestA; import example.module.SampleTestB; import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.modulith.core.ApplicationModule; import org.springframework.modulith.core.ApplicationModuleIdentifier; import org.springframework.modulith.test.ModuleContextCustomizerFactory.ModuleContextCustomizer; +import org.springframework.test.context.MergedContextConfiguration; +import org.springframework.test.context.support.AnnotationConfigContextLoader; /** * Unit tests for {@link ModuleTypeExcludeFilter}. @@ -65,4 +68,18 @@ class ModuleContextCustomizerUnitTests { assertThat(right).isEqualTo(left); assertThat(left).hasSameHashCodeAs(right); } + + @Test // GH-1110 + void registersAssertablePublishedEvents() { + + var context = new AnnotationConfigApplicationContext(); + var loader = new AnnotationConfigContextLoader(); + + new ModuleContextCustomizer(SampleTestA.class) + .customizeContext(context, new MergedContextConfiguration(SampleTestA.class, null, null, null, loader)); + + assertThat(context.getApplicationListeners()).hasSize(1) + .element(0) + .isInstanceOf(AssertablePublishedEvents.class); + } }