This is an automated email from the ASF dual-hosted git repository. aldettinger pushed a commit to branch CAMEL-13965 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 999307a36311000d46dd3b5f9811ace63ac42bc1 Author: aldettinger <aldettin...@gmail.com> AuthorDate: Tue Sep 24 18:21:45 2019 +0200 CAMEL-13965: Added the @CamelSpringBootTest annotation --- components/camel-spring-boot/pom.xml | 7 +-- .../src/main/docs/spring-boot.adoc | 52 ++++++++++++++++++++- .../MyApplicationTest.java} | 39 +++++++--------- .../apache/camel/spring/boot/example/MyRoute.java | 30 ++++++++++++ .../spring/boot/issues/StreamCachingTest.java | 4 +- .../spring/boot/mockendpoints/AdviceWithTest.java | 11 ++--- .../MockEndpointsAndSkipDirtiesContextTest.java | 9 ++-- .../boot/mockendpoints/MockEndpointsTest.java | 9 ++-- .../camel/spring/boot/routefilter/BarTest.java | 10 ++-- .../routefilter/FooExcludeRouteAnnotationTest.java | 9 ++-- .../camel/spring/boot/routefilter/FooTest.java | 7 ++- .../src/main/docs/test-spring-junit5.adoc | 1 + .../junit5/CamelSpringBootExecutionListener.java | 24 ++++++++-- ...utionListener.java => CamelSpringBootTest.java} | 32 ++++++------- ...ringTestContextLoaderTestExecutionListener.java | 23 +++++---- .../junit5/DisableJmxTestExecutionListener.java | 15 +++++- .../junit5/SpringTestExecutionListenerSorter.java | 47 +++++++++++++++++++ .../junit5/StopWatchTestExecutionListener.java | 17 ++++++- .../SpringTestExecutionListenerSorterTest.java | 54 ++++++++++++++++++++++ 19 files changed, 300 insertions(+), 100 deletions(-) diff --git a/components/camel-spring-boot/pom.xml b/components/camel-spring-boot/pom.xml index ee22f30..90b573f 100644 --- a/components/camel-spring-boot/pom.xml +++ b/components/camel-spring-boot/pom.xml @@ -102,7 +102,7 @@ <!-- Testing dependencies --> <dependency> <groupId>org.apache.camel</groupId> - <artifactId>camel-test-spring</artifactId> + <artifactId>camel-test-spring-junit5</artifactId> <scope>test</scope> </dependency> <dependency> @@ -111,11 +111,6 @@ <scope>test</scope> </dependency> <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> <groupId>org.awaitility</groupId> <artifactId>awaitility</artifactId> <scope>test</scope> diff --git a/components/camel-spring-boot/src/main/docs/spring-boot.adoc b/components/camel-spring-boot/src/main/docs/spring-boot.adoc index 05fcc26..bf247f9 100644 --- a/components/camel-spring-boot/src/main/docs/spring-boot.adoc +++ b/components/camel-spring-boot/src/main/docs/spring-boot.adoc @@ -577,7 +577,7 @@ The Rest-DSL XML files should be Camel XML rests (not CamelContext) such as ---- [[SpringBoot-Testing]] -== Testing +== Testing the JUnit 4 way For testing, Maven users will need to add the following dependencies to their `pom.xml`: [source,xml] @@ -627,3 +627,53 @@ public class MyApplicationTest { } ---- +== Testing the JUnit 5 way +For testing, Maven users will need to add the following dependencies to their `pom.xml`: + +[source,xml] +---- +<dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <version>${spring-boot.version}</version> <!-- Use the same version as your Spring Boot version --> + <scope>test</scope> +</dependency> +<dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-spring-junit5</artifactId> + <version>${camel.version}</version> <!-- use the same version as your Camel core version --> + <scope>test</scope> +</dependency> +---- + +To test a Camel Spring Boot application, annotate your test class(es) with +`@CamelSpringBootTest`. This brings Camel's Spring Test +support to your application, so that you can write tests using +https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html[Spring Boot test conventions]. + +To get the `CamelContext` or `ProducerTemplate`, you can inject them into the class in the normal Spring manner, using `@Autowired`. + +You can also use xref:manual::spring-testing.adoc[Camel Spring test annotations] to configure tests declaratively. This example uses the `@MockEndpoints` annotation to auto-mock an endpoint: + +[source,java] +---- +@CamelSpringBootTest +@SpringBootApplication +@MockEndpoints("direct:end") +public class MyApplicationTest { + + @Autowired + private ProducerTemplate template; + + @EndpointInject("mock:direct:end") + private MockEndpoint mock; + + @Test + public void testReceive() throws Exception { + mock.expectedBodiesReceived("Hello"); + template.sendBody("direct:start", "Hello"); + mock.assertIsSatisfied(); + } + +} +---- diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/BarTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/example/MyApplicationTest.java similarity index 57% copy from components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/BarTest.java copy to components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/example/MyApplicationTest.java index f563e8a..389e5e3 100644 --- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/BarTest.java +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/example/MyApplicationTest.java @@ -14,40 +14,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.spring.boot.routefilter; +package org.apache.camel.spring.boot.example; +import org.apache.camel.EndpointInject; import org.apache.camel.ProducerTemplate; import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.model.ModelCamelContext; -import org.apache.camel.test.spring.CamelSpringBootRunner; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.apache.camel.test.spring.junit5.MockEndpoints; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -@RunWith(CamelSpringBootRunner.class) +/** + * This example is included in the spring-boot.adoc "Testing the JUnit 5 way" section. + */ +@CamelSpringBootTest @SpringBootApplication -@SpringBootTest(classes = BarTest.class, - properties = {"camel.springboot.java-routes-include-pattern=**/Bar*"}) -public class BarTest { +@MockEndpoints("direct:end") +public class MyApplicationTest { @Autowired - ProducerTemplate producerTemplate; + private ProducerTemplate template; - @Autowired - ModelCamelContext camelContext; + @EndpointInject("mock:direct:end") + private MockEndpoint mock; @Test - public void shouldSendToBar() throws Exception { - // Given - MockEndpoint mock = camelContext.getEndpoint("mock:bar", MockEndpoint.class); - mock.expectedBodiesReceived("Hello Bar"); - - // When - producerTemplate.sendBody("direct:start", "Hello Bar"); - - // Then + public void testReceive() throws Exception { + mock.expectedBodiesReceived("Hello"); + template.sendBody("direct:start", "Hello"); mock.assertIsSatisfied(); } diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/example/MyRoute.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/example/MyRoute.java new file mode 100644 index 0000000..e48c401 --- /dev/null +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/example/MyRoute.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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.apache.camel.spring.boot.example; + +import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; + +@Component +public class MyRoute extends RouteBuilder { + + @Override + public void configure() throws Exception { + from("direct:start").to("direct:end"); + from("direct:end").log("done"); + } +} diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/issues/StreamCachingTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/issues/StreamCachingTest.java index 75dcaeb..8bf15ba 100644 --- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/issues/StreamCachingTest.java +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/issues/StreamCachingTest.java @@ -27,8 +27,8 @@ import org.apache.camel.EndpointInject; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.spring.boot.SpringTypeConverter; -import org.apache.camel.test.junit4.CamelTestSupport; -import org.junit.Test; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/AdviceWithTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/AdviceWithTest.java index bea0229..1b02b1b 100644 --- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/AdviceWithTest.java +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/AdviceWithTest.java @@ -21,17 +21,16 @@ import org.apache.camel.builder.AdviceWithRouteBuilder; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.model.ModelCamelContext; import org.apache.camel.reifier.RouteReifier; -import org.apache.camel.test.spring.CamelSpringBootRunner; -import org.apache.camel.test.spring.UseAdviceWith; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.apache.camel.test.spring.junit5.UseAdviceWith; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -import static org.junit.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertFalse; -@RunWith(CamelSpringBootRunner.class) +@CamelSpringBootTest @UseAdviceWith @SpringBootApplication @SpringBootTest(classes = AdviceWithTest.class) diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/MockEndpointsAndSkipDirtiesContextTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/MockEndpointsAndSkipDirtiesContextTest.java index 6133451..0a8f17e 100644 --- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/MockEndpointsAndSkipDirtiesContextTest.java +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/MockEndpointsAndSkipDirtiesContextTest.java @@ -22,17 +22,16 @@ import org.apache.camel.Produce; import org.apache.camel.ProducerTemplate; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.spring.SpringRouteBuilder; -import org.apache.camel.test.spring.CamelSpringBootRunner; -import org.apache.camel.test.spring.MockEndpointsAndSkip; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.apache.camel.test.spring.junit5.MockEndpointsAndSkip; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Configuration; import org.springframework.test.annotation.DirtiesContext; -@RunWith(CamelSpringBootRunner.class) +@CamelSpringBootTest @MockEndpointsAndSkip("direct:b") @SpringBootApplication @SpringBootTest(classes = MockEndpointsAndSkipDirtiesContextTest.class) diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/MockEndpointsTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/MockEndpointsTest.java index bacfc31..3573dfb 100644 --- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/MockEndpointsTest.java +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/mockendpoints/MockEndpointsTest.java @@ -19,15 +19,14 @@ package org.apache.camel.spring.boot.mockendpoints; import org.apache.camel.CamelContext; import org.apache.camel.FluentProducerTemplate; import org.apache.camel.component.mock.MockEndpoint; -import org.apache.camel.test.spring.CamelSpringBootRunner; -import org.apache.camel.test.spring.MockEndpoints; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.apache.camel.test.spring.junit5.MockEndpoints; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -@RunWith(CamelSpringBootRunner.class) +@CamelSpringBootTest @MockEndpoints @SpringBootApplication @SpringBootTest(classes = MockEndpointsTest.class) diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/BarTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/BarTest.java index f563e8a..396e087 100644 --- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/BarTest.java +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/BarTest.java @@ -19,17 +19,15 @@ package org.apache.camel.spring.boot.routefilter; import org.apache.camel.ProducerTemplate; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.model.ModelCamelContext; -import org.apache.camel.test.spring.CamelSpringBootRunner; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -@RunWith(CamelSpringBootRunner.class) +@CamelSpringBootTest @SpringBootApplication -@SpringBootTest(classes = BarTest.class, - properties = {"camel.springboot.java-routes-include-pattern=**/Bar*"}) +@SpringBootTest(classes = BarTest.class, properties = {"camel.springboot.java-routes-include-pattern=**/Bar*"}) public class BarTest { @Autowired diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/FooExcludeRouteAnnotationTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/FooExcludeRouteAnnotationTest.java index badc9a4..281792b 100644 --- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/FooExcludeRouteAnnotationTest.java +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/FooExcludeRouteAnnotationTest.java @@ -19,15 +19,14 @@ package org.apache.camel.spring.boot.routefilter; import org.apache.camel.ProducerTemplate; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.model.ModelCamelContext; -import org.apache.camel.test.spring.CamelSpringBootRunner; -import org.apache.camel.test.spring.ExcludeRoutes; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.apache.camel.test.spring.junit5.ExcludeRoutes; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -@RunWith(CamelSpringBootRunner.class) +@CamelSpringBootTest @SpringBootApplication() @SpringBootTest(classes = FooTest.class) @ExcludeRoutes({BarRoute.class, DrinkRoute.class}) diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/FooTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/FooTest.java index f12b309..66a3ff4 100644 --- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/FooTest.java +++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/routefilter/FooTest.java @@ -19,14 +19,13 @@ package org.apache.camel.spring.boot.routefilter; import org.apache.camel.ProducerTemplate; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.model.ModelCamelContext; -import org.apache.camel.test.spring.CamelSpringBootRunner; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -@RunWith(CamelSpringBootRunner.class) +@CamelSpringBootTest @SpringBootApplication() @SpringBootTest(classes = FooTest.class, properties = {"camel.springboot.java-routes-exclude-pattern=**/Bar*,**/Drink*"}) diff --git a/components/camel-test-spring-junit5/src/main/docs/test-spring-junit5.adoc b/components/camel-test-spring-junit5/src/main/docs/test-spring-junit5.adoc index 58717f0..31b233f 100644 --- a/components/camel-test-spring-junit5/src/main/docs/test-spring-junit5.adoc +++ b/components/camel-test-spring-junit5/src/main/docs/test-spring-junit5.adoc @@ -138,3 +138,4 @@ Tips: It's possible to run JUnit 4 & JUnit 5 based Camel Spring tests side by si * Imports of `org.apache.camel.test.spring.\*` should be replaced with `org.apache.camel.test.spring.junit5.*` * Usage of `@RunWith(CamelSpringRunner.class)` should be replaced with `@CamelSpringTest` * Usage of `@BootstrapWith(CamelTestContextBootstrapper.class)` should be replaced with `@CamelSpringTest` +* Usage of `@RunWith(CamelSpringBootRunner.class)` should be replaced with `@CamelSpringBootTest` diff --git a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringBootExecutionListener.java b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringBootExecutionListener.java index 41deaf7..898f058 100644 --- a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringBootExecutionListener.java +++ b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringBootExecutionListener.java @@ -29,6 +29,17 @@ public class CamelSpringBootExecutionListener extends AbstractTestExecutionListe private static final Logger LOG = LoggerFactory.getLogger(CamelSpringBootExecutionListener.class); + /** + * Returns the precedence that is used by Spring to choose the appropriate + * execution order of test listeners. + * + * See {@link SpringTestExecutionListenerSorter#getPrecedence(Class)} for more. + */ + @Override + public int getOrder() { + return SpringTestExecutionListenerSorter.getPrecedence(getClass()); + } + @Override public void prepareTestInstance(TestContext testContext) throws Exception { LOG.info("CamelSpringBootExecutionListener preparing: {}", testContext.getTestClass()); @@ -45,9 +56,10 @@ public class CamelSpringBootExecutionListener extends AbstractTestExecutionListe // not to start it just yet SpringCamelContext.setNoStart(true); System.setProperty("skipStartingCamelContext", "true"); - ConfigurableApplicationContext context = (ConfigurableApplicationContext) testContext.getApplicationContext(); + ConfigurableApplicationContext context = (ConfigurableApplicationContext)testContext.getApplicationContext(); - // Post CamelContext(s) instantiation but pre CamelContext(s) start setup + // Post CamelContext(s) instantiation but pre CamelContext(s) start + // setup CamelAnnotationsHandler.handleProvidesBreakpoint(context, testClass); CamelAnnotationsHandler.handleShutdownTimeout(context, testClass); CamelAnnotationsHandler.handleMockEndpoints(context, testClass); @@ -65,7 +77,7 @@ public class CamelSpringBootExecutionListener extends AbstractTestExecutionListe Class<?> testClass = testContext.getTestClass(); String testName = testContext.getTestMethod().getName(); - ConfigurableApplicationContext context = (ConfigurableApplicationContext) testContext.getApplicationContext(); + ConfigurableApplicationContext context = (ConfigurableApplicationContext)testContext.getApplicationContext(); threadApplicationContext.set(context); // mark Camel to be startable again and start Camel @@ -87,8 +99,10 @@ public class CamelSpringBootExecutionListener extends AbstractTestExecutionListe ConfigurableApplicationContext context = threadApplicationContext.get(); if (context != null && context.isRunning()) { - // dump route coverage for each test method so its accurate statistics - // even if spring application context is running (i.e. its not dirtied per test method) + // dump route coverage for each test method so its accurate + // statistics + // even if spring application context is running (i.e. its not + // dirtied per test method) CamelAnnotationsHandler.handleRouteCoverageDump(context, testClass, s -> testName); } } diff --git a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/DisableJmxTestExecutionListener.java b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringBootTest.java similarity index 50% copy from components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/DisableJmxTestExecutionListener.java copy to components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringBootTest.java index 6cc9761..c915c07 100644 --- a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/DisableJmxTestExecutionListener.java +++ b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringBootTest.java @@ -16,24 +16,22 @@ */ package org.apache.camel.test.spring.junit5; -import org.apache.camel.api.management.JmxSystemPropertyKeys; -import org.springframework.test.context.TestContext; -import org.springframework.test.context.support.AbstractTestExecutionListener; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; -/** - * Provides reset to pre-test state behavior for global enable/disable of JMX - * support in Camel through the use of {@link DisableJmx}. - * Tries to ensure that the pre-test value is restored. - */ -public class DisableJmxTestExecutionListener extends AbstractTestExecutionListener { +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.junit.jupiter.SpringExtension; - @Override - public void afterTestClass(TestContext testContext) throws Exception { - if (CamelSpringTestHelper.getOriginalJmxDisabled() == null) { - System.clearProperty(JmxSystemPropertyKeys.DISABLED); - } else { - System.setProperty(JmxSystemPropertyKeys.DISABLED, CamelSpringTestHelper.getOriginalJmxDisabled()); - } - } +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@ExtendWith(SpringExtension.class) +@TestExecutionListeners(value = {CamelSpringTestContextLoaderTestExecutionListener.class, DisableJmxTestExecutionListener.class, CamelSpringBootExecutionListener.class, + StopWatchTestExecutionListener.class}, mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS) +public @interface CamelSpringBootTest { } diff --git a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringTestContextLoaderTestExecutionListener.java b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringTestContextLoaderTestExecutionListener.java index f22d5b5..2609692 100644 --- a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringTestContextLoaderTestExecutionListener.java +++ b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/CamelSpringTestContextLoaderTestExecutionListener.java @@ -16,30 +16,29 @@ */ package org.apache.camel.test.spring.junit5; -import org.springframework.core.Ordered; import org.springframework.test.context.TestContext; import org.springframework.test.context.support.AbstractTestExecutionListener; /** - * Helper for {@link CamelSpringTestContextLoader} that sets the test class state - * in {@link CamelSpringTestHelper} almost immediately before the loader initializes - * the Spring context. + * Helper for {@link CamelSpringTestContextLoader} that sets the test class + * state in {@link CamelSpringTestHelper} almost immediately before the loader + * initializes the Spring context. * <p/> - * Implemented as a listener as the state can be set on a {@code ThreadLocal} and we are pretty sure - * that the same thread will be used to initialize the Spring context. + * Implemented as a listener as the state can be set on a {@code ThreadLocal} + * and we are pretty sure that the same thread will be used to initialize the + * Spring context. */ public class CamelSpringTestContextLoaderTestExecutionListener extends AbstractTestExecutionListener { /** - * The default implementation returns {@link org.springframework.core.Ordered#LOWEST_PRECEDENCE}, - * thereby ensuring that custom listeners are ordered after default - * listeners supplied by the framework. Can be overridden by subclasses - * as necessary. + * Returns the precedence that is used by Spring to choose the appropriate + * execution order of test listeners. + * + * See {@link SpringTestExecutionListenerSorter#getPrecedence(Class)} for more. */ @Override public int getOrder() { - //set Camel first - return Ordered.HIGHEST_PRECEDENCE; + return SpringTestExecutionListenerSorter.getPrecedence(getClass()); } @Override diff --git a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/DisableJmxTestExecutionListener.java b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/DisableJmxTestExecutionListener.java index 6cc9761..11f85b7 100644 --- a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/DisableJmxTestExecutionListener.java +++ b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/DisableJmxTestExecutionListener.java @@ -22,8 +22,8 @@ import org.springframework.test.context.support.AbstractTestExecutionListener; /** * Provides reset to pre-test state behavior for global enable/disable of JMX - * support in Camel through the use of {@link DisableJmx}. - * Tries to ensure that the pre-test value is restored. + * support in Camel through the use of {@link DisableJmx}. Tries to ensure that + * the pre-test value is restored. */ public class DisableJmxTestExecutionListener extends AbstractTestExecutionListener { @@ -36,4 +36,15 @@ public class DisableJmxTestExecutionListener extends AbstractTestExecutionListen } } + /** + * Returns the precedence that is used by Spring to choose the appropriate + * execution order of test listeners. + * + * See {@link SpringTestExecutionListenerSorter#getPrecedence(Class)} for more. + */ + @Override + public int getOrder() { + return SpringTestExecutionListenerSorter.getPrecedence(getClass()); + } + } diff --git a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/SpringTestExecutionListenerSorter.java b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/SpringTestExecutionListenerSorter.java new file mode 100644 index 0000000..08071b6 --- /dev/null +++ b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/SpringTestExecutionListenerSorter.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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.apache.camel.test.spring.junit5; + +import org.springframework.core.Ordered; + +/** + * This class centralizes the order of execution of spring test execution listeners: + * 1) StopWatchTestExecutionListener + * 2) CamelSpringBootExecutionListener + * 3) DisableJmxTestExecutionListener + * 4) CamelSpringTestContextLoaderTestExecutionListener + * 5) Spring default listeners + */ +public final class SpringTestExecutionListenerSorter { + + private SpringTestExecutionListenerSorter() { + } + + public static int getPrecedence(Class<?> clazz) { + if (clazz == StopWatchTestExecutionListener.class) { + return Ordered.HIGHEST_PRECEDENCE + 4000; + } else if (clazz == CamelSpringBootExecutionListener.class) { + return Ordered.HIGHEST_PRECEDENCE + 3000; + } else if (clazz == DisableJmxTestExecutionListener.class) { + return Ordered.HIGHEST_PRECEDENCE + 2000; + } else if (clazz == CamelSpringTestContextLoaderTestExecutionListener.class) { + return Ordered.HIGHEST_PRECEDENCE + 1000; + } + throw new IllegalArgumentException("Impossible to get the precedence of the class " + clazz.getName() + "."); + } + +} diff --git a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/StopWatchTestExecutionListener.java b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/StopWatchTestExecutionListener.java index 8b6627b..d24ba1f 100644 --- a/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/StopWatchTestExecutionListener.java +++ b/components/camel-test-spring-junit5/src/main/java/org/apache/camel/test/spring/junit5/StopWatchTestExecutionListener.java @@ -24,14 +24,27 @@ import org.springframework.test.context.TestContext; import org.springframework.test.context.support.AbstractTestExecutionListener; /** - * An execution listener that simulates the timing output built in to {@link org.apache.camel.test.junit5.CamelTestSupport}. + * An execution listener that simulates the timing output built in to + * {@link org.apache.camel.test.junit5.CamelTestSupport}. */ public class StopWatchTestExecutionListener extends AbstractTestExecutionListener { protected static ThreadLocal<StopWatch> threadStopWatch = new ThreadLocal<>(); /** - * Exists primarily for testing purposes, but allows for access to the underlying stop watch instance for a test. + * Returns the precedence that is used by Spring to choose the appropriate + * execution order of test listeners. + * + * See {@link SpringTestExecutionListenerSorter#getPrecedence(Class)} for more. + */ + @Override + public int getOrder() { + return SpringTestExecutionListenerSorter.getPrecedence(getClass()); + } + + /** + * Exists primarily for testing purposes, but allows for access to the + * underlying stop watch instance for a test. */ public static StopWatch getStopWatch() { return threadStopWatch.get(); diff --git a/components/camel-test-spring-junit5/src/test/java/org/apache/camel/test/spring/SpringTestExecutionListenerSorterTest.java b/components/camel-test-spring-junit5/src/test/java/org/apache/camel/test/spring/SpringTestExecutionListenerSorterTest.java new file mode 100644 index 0000000..e3d1ca3 --- /dev/null +++ b/components/camel-test-spring-junit5/src/test/java/org/apache/camel/test/spring/SpringTestExecutionListenerSorterTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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.apache.camel.test.spring; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.camel.test.spring.junit5.CamelSpringBootExecutionListener; +import org.apache.camel.test.spring.junit5.CamelSpringTestContextLoaderTestExecutionListener; +import org.apache.camel.test.spring.junit5.DisableJmxTestExecutionListener; +import org.apache.camel.test.spring.junit5.StopWatchTestExecutionListener; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.test.spring.junit5.SpringTestExecutionListenerSorter.getPrecedence; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class SpringTestExecutionListenerSorterTest { + + @Test + void getPrecedencesForRegisteredClassesShouldReturnCorrectOrder() { + + ArrayList<Class<?>> listenersInExpectedOrder = new ArrayList<>(); + listenersInExpectedOrder.add(StopWatchTestExecutionListener.class); + listenersInExpectedOrder.add(CamelSpringBootExecutionListener.class); + listenersInExpectedOrder.add(DisableJmxTestExecutionListener.class); + listenersInExpectedOrder.add(CamelSpringTestContextLoaderTestExecutionListener.class); + + List<Class<?>> listenersSortedByPrecedence = new ArrayList<>(listenersInExpectedOrder); + listenersSortedByPrecedence.sort((c1, c2) -> Integer.compare(getPrecedence(c2), getPrecedence(c1))); + + assertEquals(listenersInExpectedOrder, listenersSortedByPrecedence); + } + + @Test + void getPrecedenceForWrongClassShouldThrow() { + assertThrows(IllegalArgumentException.class, () -> getPrecedence(Object.class)); + } + +}