이 콘텐츠는 선택한 언어로 제공되지 않습니다.

Chapter 5. Testing routes in Camel Quarkus


5.1. Testing Camel Quarkus Extensions

Testing offers a good way to ensure Camel routes behave as expected over time. If you haven’t already, read the Camel Quarkus user guide First Steps and the Quarkus documentation Testing your application section.

When it comes to testing a route in the context of Quarkus, the recommended approach is to write local integration tests. This has the advantage of covering both JVM and native mode.

In JVM mode, you can use the CamelTestSupport style of testing.

5.1.1. Running in JVM mode

In JVM mode, use the @QuarkusTest annotation to bootstrap Quarkus and start Camel routes before the @Test logic executes.

For example:

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

@QuarkusTest
class MyTest {
    @Test
    public void test() {
        // Use any suitable code that sends test data to the route and then assert outcomes
        ...
    }
}
Copy to Clipboard Toggle word wrap
Tip

You can find a sample implementation in the Camel Quarkus source:

5.1.2. Running in native mode

Note

Always test that your application works in native mode for all supported extensions.

You can reuse the test logic defined for JVM mode by inheriting the logic from the respective JVM mode class.

Add the @QuarkusIntegrationTest annotation to tell the Quarkus JUnit extension to compile the application under test to native image and start it before running the tests.

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
class MyIT extends MyTest {
   ...
}
Copy to Clipboard Toggle word wrap
Tip

You can find a sample implementation in the Camel Quarkus source:

5.1.3. Differences between @QuarkusTest and @QuarkusIntegrationTest

A native executable does not need a JVM to run, and cannot run in a JVM, because it is native code, not bytecode.

There is no point in compiling tests to native code so they run using a traditional JVM.

This means that communication between tests and the application must go over the network (HTTP/REST, or any other protocol your application speaks), through watching filesystems (log files for example), or any other interprocess communication.

5.1.3.1. @QuarkusTest in JVM mode

In JVM mode, tests annotated with @QuarkusTest execute in the same JVM as the application under test.

This means you can use @Inject to add beans from the application into the test code.

You can also define new beans or even override the beans from the application using @jakarta.enterprise.inject.Alternative and @jakarta.annotation.Priority.

5.1.3.2. @QuarkusIntegrationTest in native mode

In native mode, tests annotated with @QuarkusIntegrationTest execute in a JVM hosted in a process separate from the running native application.

An important consequence of this, is that all communication between the tests and the native application, must take one or more of the following forms:

  • Network calls. Typically, HTTP or any other network protocol your application supports.
  • Watching the filesystem for changes. (For example via Camel file endpoints.)
  • Any other kind of interprocess communication.

QuarkusIntegrationTest provides additional features that are not available through @QuarkusTest:

  • In JVM mode, you can launch and test the runnable application JAR produced by the Quarkus build.
  • In native mode, you can launch and test the native application produced by the Quarkus build.
  • If you add a container image to the build, a container starts, and tests execute against it.

For more information about QuarkusIntegrationTest, see the Quarkus testing guide.

5.1.4. Testing with external services

5.1.4.1. Testcontainers

Sometimes your application needs to access some external resource, such as a messaging broker, a database, or other service.

If a container image is available for the service of interest, you can use Testcontainers to start and configure the services during testing.

5.1.4.1.1. Passing configuration data with QuarkusTestResourceLifecycleManager

For the application to work properly, it is often essential to pass the connection configuration data (host, port, user, password of the remote service) to the application before it starts.

In the Quarkus ecosystem, QuarkusTestResourceLifecycleManager serves this purpose.

You can start one or more Testcontainers in the start() method and return the connection configuration from the method in the form of a Map.

The entries of this map are then passed to the application in different ways depending on the mode:

  • Native mode: a command line (-Dkey=value)
  • JVM Mode: a special MicroProfile configuration provider
Note

Command line and MicroProfile settings have a higher precedence than the settings in the application.properties file.

import java.util.Map;
import java.util.HashMap;

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;

public class MyTestResource implements QuarkusTestResourceLifecycleManager {

    private GenericContainer<?> myContainer;

    @Override
    public Map<String, String> start() {
        // Start the needed container(s)
        myContainer = new GenericContainer(DockerImageName.parse("my/image:1.0.0"))
                .withExposedPorts(1234)
                .waitingFor(Wait.forListeningPort());

        myContainer.start();

        // Pass the configuration to the application under test
        // You can also pass camel component property names / values to automatically configure Camel components
        return new HashMap<>() {{
                put("my-container.host", container.getHost());
                put("my-container.port", "" + container.getMappedPort(1234));
        }};
    }

    @Override
    public void stop() {
        // Stop the needed container(s)
        myContainer.stop();
        ...
    }
}
Copy to Clipboard Toggle word wrap

Reference the defined test resource from the test classes with @QuarkusTestResource:

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
@QuarkusTestResource(MyTestResource.class)
class MyTest {
   ...
}
Copy to Clipboard Toggle word wrap
Tip

You can find a sample implementation in the Camel Quarkus source:

5.1.4.2. WireMock

Instead of having the tests connect to live endpoints, for example, if they are unavailable, unreliable, or expensive, you can stub HTTP interactions with third-party services & APIs.

You can use WireMock for mocking & recording HTTP interactions. It is used extensively throughout the Camel Quarkus test suite for various component extensions.

5.1.4.2.1. Setting up WireMock

Procedure

  1. Set up the WireMock server.

    Note

    Always configure the Camel component under test to pass any HTTP interactions through the WireMock proxy. You can achieve this by configuring a component property that determines the API endpoint URL.

    import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
    import static com.github.tomakehurst.wiremock.client.WireMock.get;
    import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
    import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import com.github.tomakehurst.wiremock.WireMockServer;
    
    import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
    
    public class WireMockTestResource implements QuarkusTestResourceLifecycleManager {
    
        private WireMockServer server;
    
        @Override
        public Map<String, String> start() {
            // Setup & start the server
            server = new WireMockServer(
                wireMockConfig().dynamicPort()
            );
            server.start();
    
            // Stub an HTTP endpoint. WireMock also supports a record and playback mode
            // https://wiremock.org/docs/record-playback/
            server.stubFor(
                get(urlEqualTo("/api/greeting"))
                    .willReturn(aResponse()
                        .withHeader("Content-Type", "application/json")
                        .withBody("{\"message\": \"Hello World\"}")));
    
            // Ensure the camel component API client passes requests through the WireMock proxy
            Map<String, String> conf = new HashMap<>();
            conf.put("camel.component.foo.server-url", server.baseUrl());
            return conf;
        }
    
        @Override
        public void stop() {
            if (server != null) {
                server.stop();
            }
        }
    }
    Copy to Clipboard Toggle word wrap
  2. Ensure your test class has the @QuarkusTestResource annotation with the appropriate test resource class specified as the value. The WireMock server will be started before all tests are executed and will be shut down when all tests are finished.
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
@QuarkusTestResource(WireMockTestResource.class)
class MyTest {
   ...
}
Copy to Clipboard Toggle word wrap

The WireMock server starts before all tests execute and shuts down when all tests finish.

Tip

You can find a sample implementation in the Camel Quarkus integration test source tree:

5.1.5. CamelTestSupport style of testing with CamelQuarkusTestSupport

Since Camel Quarkus 2.13.0, you can use CamelQuarkusTestSupport for testing. It is a replacement for CamelTestSupport, which does not work well with Quarkus.

Important

CamelQuarkusTestSupport only works in JVM mode. If you need to test in native mode, then use one of the alternate test strategies described above.

5.1.5.1. Testing with CamelQuarkusTestSupport in JVM mode

Add the following dependency into your module (preferably in the test scope):

<dependency>
    <groupId>org.apache.camel.quarkus</groupId>
    <artifactId>camel-quarkus-junit5</artifactId>
    <scope>test</scope>
</dependency>
Copy to Clipboard Toggle word wrap

You can use CamelQuarkusTestSupport in your test like this:

@QuarkusTest
@TestProfile(SimpleTest.class) //necessary only if "newly created" context is required for the test (worse performance)
public class SimpleTest extends CamelQuarkusTestSupport {
    ...
}
Copy to Clipboard Toggle word wrap

5.1.5.2. Customizing the CamelContext for testing

You can customize the CamelContext for testing with configuration profiles, CDI beans, observers, mocks etc. You can also override the createCamelContext method and interact directly with the CamelContext.

Important

When using createCamelContext you MUST NOT instantiate and return a new CamelContext. Instead, invoke super.createCamelContext() and modify the returned CamelContext as needed. Failing to follow this rule will result in an exception being thrown.

@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {

    @Override
    protected CamelContext createCamelContext() throws Exception {
        // Must call super to get a handle on the application scoped CamelContext
        CamelContext context = super.createCamelContext();
        // Apply customizations
        context.setTracing(true);
        // Return the modified CamelContext
        return context;
    }
}
Copy to Clipboard Toggle word wrap

5.1.5.3. Configuring routes for testing

Any classes that extend RouteBuilder in your application will have their routes automatically added to the CamelContext. Similarly, any XML or YAML routes configured from camel.main.routes-include-pattern will also be loaded.

This may not always be desirable for your tests. You control which routes get loaded at test time with configuration properties:

  • quarkus.camel.routes-discovery.include-patterns
  • quarkus.camel.routes-discovery.exclude-patterns,
  • camel.main.routes-include-pattern
  • camel.main.routes-exclude-pattern.

You can also define test specific routes per test class by overriding createRouteBuilder:

@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {
    @Test
    void testGreeting() {
        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
        mockEndpoint.expectedBodiesReceived("Hello World");

        template.sendBody("direct:start", "World");

        mockEndpoint.assertIsSatisified();
    }

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("direct:start")
                    .transform().simple("Hello ${body}")
                    .to("mock:result");
            }
        };
    }
}
Copy to Clipboard Toggle word wrap

5.1.5.4. CamelContext test lifecycle

One of the main differences in CamelQuarkusTestSupport compared to CamelTestSupport is how the CamelContext lifecycle is managed.

On Camel Quarkus, a single CamelContext is created for you automatically by the runtime. By default, this CamelContext is shared among all tests and remains started for the duration of the entire test suite execution.

This can potentially have some unintended side effects for your tests. If you need to have the CamelContext restarted between tests, then you can create a custom test profile, which will force the application under test to be restarted.

For example, to define a test profile:

@QuarkusTest
class MyTestProfile implements QuarkusTestProfile {
    ...
}
Copy to Clipboard Toggle word wrap

Then reference it on the test class with @TestProfile:

// @TestProfile will trigger the application to be restarted
@TestProfile(MyTestProfile.class)
@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {
    ...
}
Copy to Clipboard Toggle word wrap
Note

You cannot manually restart the CamelContext by invoking its stop() and start() methods. This will result in an exception.

5.1.5.5. Examples

5.1.5.5.1. Simple RouteBuilder and test class

Simple RouteBuilder:

public class MyRoutes extends RouteBuilder {
    @Override
    public void configure() {
        from("direct:start")
            .transform().simple("Hello ${body}")
            .to("mock:result");
    }
}
Copy to Clipboard Toggle word wrap

Test sending a message payload to the direct:start endpoint:

@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {
    @Test
    void testGreeting() {
        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
        mockEndpoint.expectedBodiesReceived("Hello World");

        template.sendBody("direct:start", "World");

        mockEndpoint.assertIsSatisified();
    }
}
Copy to Clipboard Toggle word wrap
5.1.5.5.2. Using AdviceWith
@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {
    @BeforeEach
    public void beforeEach() throws Exception {
        AdviceWith.adviceWith(this.context, "advisedRoute", route -> {
            route.replaceFromWith("direct:replaced");
        });
    }

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("direct:start").routeId("advisedRoute")
                    .transform().simple("Hello ${body}")
                    .to("mock:result");
            }
        };
    }

    @Test
    void testAdvisedRoute() throws Exception {
        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
        mockEndpoint.expectedBodiesReceived("Hello World");

        template.sendBody("direct:replaced", "World");

        mockEndpoint.assertIsSatisfied();
    }
}
Copy to Clipboard Toggle word wrap
5.1.5.5.3. Explicitly enabling advice

When explicitly enabling advice you must invoke startRouteDefinitions when completing your AdviceWith setup.

Note

Invoking startRouteDefinitions is only required if you have routes configured that are NOT being advised.

5.1.5.6. Limitations

5.1.5.6.1. Test lifecycle methods inherited from CamelTestSupport

CamelQuarkusTestSupport inherits some test lifecycle methods from CamelTestSupport. However, they should not be used and instead are replaced with equivalent methods in CamelQuarkusTestSupport.

Expand
CamelTestSupport lifecycle methodsCamelQuarkusTestSupport equivalent

afterAll

doAfterAll

afterEach, afterTestExecution

doAfterEach

beforeAll

doAfterConstruct

beforeEach

doBeforeEach

5.1.5.6.2. Creating a custom Camel registry is not supported

The CamelQuarkusTestSupport implementation of createCamelRegistry will throw UnsupportedOperationException.

If you need to bind or unbind objects to the Camel registry, then you can do it by one of the following methods.

  • Produce named CDI beans

    public class MyBeanProducers {
        @Produces
        @Named("myBean")
        public MyBean createMyBean() {
            return new MyBean();
        }
    }
    Copy to Clipboard Toggle word wrap
  • Override createCamelContext (see example above) and invoke camelContext.getRegistry().bind("foo", fooBean)
  • Use the @BindToRegistry annotation

    @QuarkusTest
    class SimpleTest extends CamelQuarkusTestSupport {
        @BindToRegistry("myBean")
        MyBean myBean = new MyBean();
    }
    Copy to Clipboard Toggle word wrap
    Note

    Beans bound to the Camel registry from individual test classes, will persist for the duration of the test suite execution. This could have unintended consequences, depending on your test expectations. You can use test profiles to restart the CamelContext to avoid this.

Red Hat logoGithubredditYoutubeTwitter

자세한 정보

평가판, 구매 및 판매

커뮤니티

Red Hat 문서 정보

Red Hat을 사용하는 고객은 신뢰할 수 있는 콘텐츠가 포함된 제품과 서비스를 통해 혁신하고 목표를 달성할 수 있습니다. 최신 업데이트를 확인하세요.

보다 포괄적 수용을 위한 오픈 소스 용어 교체

Red Hat은 코드, 문서, 웹 속성에서 문제가 있는 언어를 교체하기 위해 최선을 다하고 있습니다. 자세한 내용은 다음을 참조하세요.Red Hat 블로그.

Red Hat 소개

Red Hat은 기업이 핵심 데이터 센터에서 네트워크 에지에 이르기까지 플랫폼과 환경 전반에서 더 쉽게 작업할 수 있도록 강화된 솔루션을 제공합니다.

Theme

© 2026 Red Hat
맨 위로 이동