Icon for gfsd IntelliJ IDEA

Generating unit tests for Java projects with Maven dependencies

Symflower and Maven: a couple in love ❤

Symflower allows you to analyze and automatically generate unit tests for Java projects which rely on Maven dependencies. Let us have a look at how that plays out in practice.

Project Setup

We are going to create a Java project with the following structure containing a Maven POM file (pom.xml) and a Java source file called StringUtilsTester.java.

~/projects/test-java-maven
├── pom.xml
└── src
    └── main
        └── java
            └── at
                └── symflower
                    └── commons
                        └── strings
                            └── StringUtilsTester.java

The POM file contains project metadata but also a set of dependencies, in our case a dependency to org.apache.commons.commons-lang3. Please note, the biggest chunk of the POM file is there so you can use mvn test to execute tests Symflower will generate.

<?xml version="1.0" encoding="UTF-8"?>
<project>
	<modelVersion>4.0.0</modelVersion>

	<groupId>at.symflower</groupId>
	<artifactId>commons</artifactId>
	<version>0.0.0</version>

	<dependencies>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.0</version>
		</dependency>
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-engine</artifactId>
			<version>5.5.2</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>3.0.0-M8</version>
			</plugin>
		</plugins>
	</build>
</project>

The Java source class StringUtilsTester.java makes use of the specified dependency by importing StringUtils from org.apache.commons.lang3. The function lazyTrim(String) only calls StringUtils.trim(String) if the input is not null, if it is not an empty string, and if there are space characters at the beginning and end of the given string.

package at.symflower.commons.strings;

import org.apache.commons.lang3.StringUtils;

public final class StringUtilsTester {
    public static String lazyTrim(String input) {
        if (input == null || input.length() == 0) {
            return "";
        }

        if (input.charAt(0) != ' ' || input.charAt(input.length() - 1) != ' ') {
            return input;
        }

        return StringUtils.trim(input);
    }
}

Generating Unit Tests

We use JetBrains' IntelliJ IDEA as our editor in this example, but you can also use other integrations, such as VS Code or Symflower CLI in your terminal, to generate the unit tests.

Make sure that the “Fetch Dependencies” option is activated for the Symflower plugin in your editor.

Unit tests are generated by triggering the corresponding command. The command we want to use is called Symflower: Generate Unit Tests for File and can be found in the command palette (CTRL+SHIFT+A in IntelliJ or CTRL+SHIFT+P in VS Code).

Generate unit tests in IntelliJ.
The first time a project with dependencies is analyzed, Symflower has to download and analyze the dependencies as well. In other words, generating unit tests for the first time takes slightly longer than afterwards when the dependencies are cached.

The generated tests can then be found in a file called StringUtilsTesterSymflowerTest.java which is located in the test directory specified by the Maven project. By convention, the project structure looks like this:

~/projects/test-java-maven
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── at
    │           └── symflower
    │               └── commons
    │                   └── strings
    │                       └── StringUtilsTester.java
    └── test
        └── java
            └── at
                └── symflower
                    └── commons
                        └── strings
                            └── StringUtilsTesterSymflowerTest.java

If you want to read about best practices and conventions regarding Java test files, feel free to take a look at our previous blog post Best practices for test files in Go and Java.

Here is an excerpt of the tests that have been generated by Symflower for the function StringUtilsTester.lazyTrim(String).

package at.symflower.commons.strings;

import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;

public class StringUtilsTesterSymflowerTest {
	@Test
	public void lazyTrim1() {
		String input = null;
		String expected = "";
		String actual = StringUtilsTester.lazyTrim(input);

		assertEquals(expected, actual);
	}

	@Test
	public void lazyTrim2() {
		String input = "";
		String expected = "";
		String actual = StringUtilsTester.lazyTrim(input);

		assertEquals(expected, actual);
	}

	@Test
	public void lazyTrim3() {
		String input = " R";
		String expected = " R";
		String actual = StringUtilsTester.lazyTrim(input);

		assertEquals(expected, actual);
	}

	@Test
	public void lazyTrim4() {
		String input = "~";
		String expected = "~";
		String actual = StringUtilsTester.lazyTrim(input);

		assertEquals(expected, actual);
	}

	@Test
	public void lazyTrim5() {
		String input = " ";
		String expected = "";
		String actual = StringUtilsTester.lazyTrim(input);

		assertEquals(expected, actual);
	}
}

Is this how you are expecting a lazy-trim to work? Change the implementation and generate the tests again, until you are satisfied with the behavior.

Feedback

Found something useful in this article? Great! Perhaps you would also enjoy Symflower for IntelliJ IDEA, GoLand, Android Studio, and of course VS Code to help with writing and maintaining software tests. You’re also invited to join our newsletter where we post insights into software development and testing.

If you have any questions or feedback for our articles or our plugin, we’d love to hear from you! You can send us an hello@symflower.com or find us on social media.

| 2023-02-13