Running Unit Tests and Integration Tests Separately in Spring Boot

This tutorial will guide you through the process of running Unit Tests and Integration Tests separately in a Maven-based Spring Boot application. We will use the JUnit Tag feature to group our test cases and separate Unit Tests from Integration Tests.

To learn more, check out the Test Java code tutorials page.

Create your tests

In this tutorial, we will be grouping our tests into Unit Tests and Integration Tests. A Unit Test is a type of test that focuses on a small, isolated part of your application, typically a single function or method. On the other hand, an Integration Test checks the interactions between different parts of your application, such as service calls or data integrations.

By convention, we will name our test classes following this pattern:

  • Unit Tests: *Test.java
  • Integration Tests: *IntegrationTest.java

For example, you might have UserServiceTest.java as a Unit Test, and UserServiceIntegrationTest.java as an Integration Test.

Tag your tests

With JUnit Jupiter, you can tag your test methods or test classes using the @Tag annotation. We will use the tags “Unit” for Unit Tests, and “Integration” for Integration Tests.

Example for Unit Test:

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

@Tag("Unit")
public class UserServiceTest {
    @Test
    void someUnitTest() {
        // Your test code here
    }
}

Example for Integration Test:

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

@Tag("Integration")
public class UserServiceIntegrationTest {
    @Test
    void someIntegrationTest() {
        // Your test code here
    }
}

Configure Maven to run Unit tests and Integration tests separately

To tell Maven how to run Unite tests separately from Integration tests, we will define some configurations in the pom.xml file of our project. The key here is to use the maven-surefire-plugin for Unit Tests, and the maven-failsafe-plugin for Integration Tests.

Here is how our pom.xml file looks:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.appsdeveloperblog</groupId>
    <artifactId>RunTestsSeparately</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>RunTestsSeparately</name>
    <description>Run Integration Tests separate from Unit Tests</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>2.22.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>unit-tests</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>2.22.2</version>
                        <configuration>
                            <skip>false</skip>
                            <groups>Unit</groups>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>

        <profile>
            <id>integration-tests</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-failsafe-plugin</artifactId>
                        <version>2.22.2</version>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>integration-test</goal>
                                    <goal>verify</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <skip>false</skip>
                            <includes>
                                <include>**/*IntegrationTest.java</include>
                            </includes>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

Let’s delve deeper into the <build> and <profiles> sections of the pom.xml file.

  1. <build> Section:The <build> section is where you can configure project build settings, like directory structure and build plugins.Here, you are using two plugins: maven-surefire-plugin and maven-failsafe-plugin.
    • maven-surefire-plugin: This plugin is used during the test phase of the build lifecycle to execute the unit tests of an application. It is invoked when you run the command mvn test.
    • maven-failsafe-plugin: This plugin is designed to run integration tests while ensuring that failures do not halt the build. It is typically used with the mvn verify command.

    In your <build> configuration, you’ve set <skip>true</skip> for the maven-surefire-plugin, meaning that by default, the unit tests will not be executed during the build. The maven-failsafe-plugin is configured without a skip option, meaning the integration tests will be run unless specified otherwise.

  2. <profiles> Section:Maven profiles are a set of configuration values which can be used to set or override default values of Maven build. They are typically used for different build environments (like production, development, etc.), but here you are using them to separate the execution of unit tests from integration tests.You have two profiles: unit-tests and integration-tests.
    • unit-tests: This profile reactivates the maven-surefire-plugin by setting <skip>false</skip>, and it specifies that only tests tagged with “Unit” should be included in the run. This profile is activeByDefault, meaning it will be used when no profiles are explicitly activated.
    • integration-tests: This profile configures the maven-failsafe-plugin to include any test classes that end with IntegrationTest.java in the name.

So, when you run mvn test, Maven activates the unit-tests profile by default and runs only the unit tests.

When you run mvn verify -Pintegration-tests, Maven activates the integration-tests profile and runs only the integration tests.

This configuration allows you to run your unit and integration tests separately, giving you more control over your testing strategy.

Run your tests

Now that our Maven configuration is set up, we can run our tests separately.

Running Unit Tests

To run Unit Tests, use the following command in the terminal:

mvn test

Running Integration Tests

To run Integration Tests, use the following command:

mvn verify -Pintegration-tests

Note that when we run the Integration Tests, the Unit Tests are skipped, because we have configured our pom.xml file that way.

Conclusion

Congratulations on reaching the end of this tutorial! Let’s recap the key takeaways from this learning journey:

  1. Test Annotations: You’ve learned how to use JUnit 5’s @Tag annotation to distinguish between unit tests and integration tests, helping to keep your test cases organized.
  2. Maven Profiles: You now know how to use Maven profiles to control which tests get run during your build process. The unit-tests and integration-tests profiles you’ve set up make running separate tests a breeze.
  3. Maven Plugins: You’ve seen how the maven-surefire-plugin and maven-failsafe-plugin can be configured to handle unit tests and integration tests, respectively.
  4. Running Tests: You’re now able to run unit tests and integration tests separately in a Maven-based Spring Boot application, giving you more flexibility and control over your testing strategy.

With these skills, you’ve taken your understanding of testing in Spring Boot to the next level.

Interested in digging deeper into testing in Java? Be sure to check out our Test Java code tutorials page for more helpful guides and insights. Happy coding!