eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

eBook – Maven – NPI (cat=Maven)
announcement - icon

Get up to speed with the core of Maven quickly, and then go beyond the foundations into the more powerful functionality of the build tool, such as profiles, scopes, multi-module projects and quite a bit more:

>> Download the core Maven eBook

Partner – Diagrid – NPI (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Overview

Maven is the most popular build tool in the Java space, while integration testing is an essential part of the development process. Therefore, it’s a natural choice to configure and execute integration tests with Maven.

In this tutorial, we’ll go over a number of different ways to use Maven for integration testing and to separate integration tests from unit tests.

2. Preparation

To make the demonstration code close to a real-world project, we’ll set up a JAX-RS application. This application is deployed to a server before the execution of integration tests and dismantled afterward.

2.1. Maven Configuration

We’ll build our REST application around Jersey – the reference implementation of JAX-RS. This implementation requires a couple of dependencies:

<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet-core</artifactId>
    <version>2.27</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.inject</groupId>
    <artifactId>jersey-hk2</artifactId>
    <version>2.27</version>
</dependency>

We can find the latest versions of these dependencies here and here.

We’ll use the Jetty Maven plugin to set up a testing environment. This plugin starts a Jetty server during the pre-integration-test phase of the Maven build lifecycle, then stops it in the post-integration-test phase.

Here’s how we configure the Jetty Maven plugin in pom.xml:

<plugin>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>9.4.11.v20180605</version>
    <configuration>
        <httpConnector>
            <port>8999</port>
        </httpConnector>
        <stopKey>quit</stopKey>
        <stopPort>9000</stopPort>
    </configuration>
    <executions>
        <execution>
            <id>start-jetty</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>start</goal>
            </goals>
        </execution>
        <execution>
            <id>stop-jetty</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>

When the Jetty server starts up, it’ll be listening on port 8999. The stopKey and stopPort configuration elements are used solely by the plugin’s stop goal and their value isn’t important from our perspective.

Here is where to find the latest version of the Jetty Maven plugin.

Another thing to notice is that we must set the packaging element in the pom.xml file to war, otherwise the Jetty plugin cannot start the server:

<packaging>war</packaging>

2.2. Creating a REST Application

The application endpoint is very simple – returning a welcome message when a GET request hits the context root:

@Path("/")
public class RestEndpoint {
    @GET
    public String hello() {
        return "Welcome to Baeldung!";
    }
}

This is how we register the endpoint class with Jersey:

package com.baeldung.maven.it;

import org.glassfish.jersey.server.ResourceConfig;

public class EndpointConfig extends ResourceConfig {
    public EndpointConfig() {
        register(RestEndpoint.class);
    }
}

To have the Jetty server aware of our REST application, we can use a classic web.xml deployment descriptor:

<web-app 
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
  http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1">
    <servlet>
        <servlet-name>rest-servlet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.baeldung.maven.it.EndpointConfig</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>rest-servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

This descriptor must be placed in the directory /src/main/webapp/WEB-INF to be recognized by the server.

2.3. Client-Side Test Code

All test classes in the following sections contain a single method:

@Test
public void whenSendingGet_thenMessageIsReturned() throws IOException {
    String url = "http://localhost:8999";
    URLConnection connection = new URL(url).openConnection();
    try (InputStream response = connection.getInputStream();
      Scanner scanner = new Scanner(response)) {
        String responseBody = scanner.nextLine();
        assertEquals("Welcome to Baeldung!", responseBody);
    }
}

As we can see, this method does nothing but sending a GET request to the web application we set up before and verifying the response.

3. Integration Testing in Action

An important thing to notice about integration testing is that test methods often take quite a long time to run.

As a result, we should exclude integration tests from the default build lifecycle, keeping them from slowing down the whole process each time we build a project.

A convenient way to separate integration tests is to use build profiles. This kind of configuration enables us to execute integration tests only when necessary – by specifying a suitable profile.

In the sections that follow, we’ll configure all integration tests with build profiles.

4. Testing With the Failsafe Plugin

The simplest way to run integration tests is to use the Maven failsafe plugin.

By default, the Maven surefire plugin executes unit tests during the test phase, while the failsafe plugin runs integration tests in the integration-test phase.

We can name test classes with different patterns for those plugins to pick up the enclosed tests separately.

The default naming conventions enforced by surefire and failsafe are different, thus we just need to follow these conventions to segregate unit and integration tests.

The execution of the surefire plugin includes all classes whose name starts with Test, or ends with Test, Tests or TestCase. In contrast, the failsafe plugin executes test methods in classes whose name starts with IT, or ends with IT or ITCase.

This is where we can find the documentation regarding test inclusion for surefire, and here is the one for failsafe.

Let’s add the failsafe plugin to the POM with default configuration:

<profile>
    <id>failsafe</id>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>3.1.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

This link is where to find the latest version of the failsafe plugin.

With the above configuration, the following test method will be executed in the integration-test phase:

public class RestIT {
    // test method shown in subsection 2.3
}

Since the Jetty server starts up in the pre-integration-test phase and shuts down in post-integration-test, the test we have just seen passes with this command:

mvn verify -Pfailsafe

We can also customize the naming patterns to include classes with different names:

<plugin>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>3.1.2</version>
    <configuration>
        <includes>
            <include>**/*RestIT</include>
            <include>**/RestITCase</include>
        </includes>
    </configuration>
    ...
</plugin>

5. Testing With the Surefire Plugin

Apart from the failsafe plugin, we can also use the surefire plugin to execute unit and integration tests in different phases.

Let’s assume we want to name all integration tests with the suffix IntegrationTest. Since the surefire plugin runs tests with such a name in the test phase by default, we need to exclude them from the default execution:

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.2.5</version>
    <configuration>
        <excludes>
            <exclude>**/*IntegrationTest</exclude>
        </excludes>
    </configuration>
</plugin>

The latest version of this plugin is here.

We’ve taken all test classes having a name ending with IntegrationTest out of the build lifecycle. It’s time to put them back with a profile:

<profile>
    <id>surefire</id>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.2.5</version>
                <executions>
                    <execution>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <configuration>
                            <excludes>
                                <exclude>none</exclude>
                            </excludes>
                            <includes>
                                <include>**/*IntegrationTest</include>
                            </includes>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

Instead of binding the test goal of the surefire plugin to the test build phase, as usual, we bound it to the integration-test phase. The plugin will then kick in during the integration testing process.

Notice that we must set an exclude element to none to override the exclusion specified in the base configuration.

Now, let’s define an integration test class with our naming pattern:

public class RestIntegrationTest {
    // test method shown in subsection 2.3
}

This test will be running with the command:

mvn verify -Psurefire

6. Testing With the Cargo Plugin

We can use the surefire plugin with the Maven cargo plugin. This plugin comes with built-in support for embedded servers, which are very useful for integration testing.

More details about this combination can be found here.

7. Testing With JUnit’s @Category

A convenient way to selectively execute tests is to leverage the @Category annotation in the JUnit 4 framework. This annotation lets us exclude particular tests from unit testing, and include them in integration testing.

First off, we need an interface or class to work as a category identifier:

package com.baeldung.maven.it;

public interface Integration { }

We can then decorate a test class with the @Category annotation and Integration identifier:

@Category(Integration.class)
public class RestJUnitTest {
    // test method shown in subsection 2.3
}

Rather than declaring the @Category annotation on a test class, we can also use it at the method level to categorize individual test methods.

Excluding a category from the test build phase is simple:

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.2.5</version>
    <configuration>
        <excludedGroups>com.baeldung.maven.it.Integration</excludedGroups>
    </configuration>
</plugin>

Including the Integration category in the integration-test phase is also straightforward:

<profile>
    <id>category</id>
        <build>
        <plugins>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>3.1.2</version>
                <configuration>
                    <includes>
                        <include>**/*</include>
                    </includes>
                    <groups>com.baeldung.maven.it.Integration</groups>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

We can now run integration tests with a Maven command:

mvn verify -Pcategory

8. Adding a Separate Directory for Integration Tests

It’s desirable at times to have a separate directory for integration tests. Organizing tests this way allows us to entirely isolate integration tests from unit tests.

We can use the Maven build helper plugin for this purpose:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>3.0.0</version>
    <executions>
        <execution>
            <id>add-integration-test-source</id>
            <phase>generate-test-sources</phase>
            <goals>
                <goal>add-test-source</goal>
            </goals>
            <configuration>
                <sources>
                    <source>src/integration-test/java</source>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>

Here is where we can find the latest version of this plugin.

The configuration we’ve just seen adds a test source directory to the build. Let’s add a class definition to that new directory:

public class RestITCase {
    // test method shown in subsection 2.3
}

It’s time to run integration tests in this class:

mvn verify -Pfailsafe

The Maven failsafe plugin will execute methods in this test class due to the configuration we set in subsection 3.1.

A test source directory often goes with a resource directory. We can add such a directory in another execution element to the plugin configuration:

<executions>
    ...
    <execution>
        <id>add-integration-test-resource</id>
        <phase>generate-test-resources</phase>
        <goals>
            <goal>add-test-resource</goal>
        </goals>
        <configuration>
            <resources>
                <resource>
                    <directory>src/integration-test/resources</directory>
                </resource>
            </resources>
        </configuration>
    </execution>
</executions>

9. Conclusion

This article went over using Maven to run integration tests with a Jetty server, focusing on the configuration of the Maven surefire and failsafe plugins.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)