When applying unit testing on your software, you’ll likely end up with lots of unit tests. In order to stay organized so that your test package structure is transparent and easy for other collaborators to work with, you’ll need to establish a Java (or Go) test naming convention for your unit tests, and you’ll also need to define a Java (or Go) test directory where you’ll be storing those tests. A logical test package structure as well as sound unit test naming conventions make navigation easier for others working with your code.
The test naming convention, as well as the test folder structure you use depends on the programming language, tools, settings and options used for a project. In this article we will take a look at some key best practices for defining Go and Java unit test naming conventions and test folder structures. We will also cover how Symflower can be configured to change your project’s conventions of naming and locating unit test files.
Go best practices for naming and storing unit test files
Go’s testing facilities are directly built into the language. In order for the go test
command to recognize a file that contains tests, the file suffix _test.go
has to be used. By convention a file named src/mypackage/plain.go
has the associated test file src/mypackage/plain_test.go
. However, as this is just a convention, Go neither constrains you to place the test file in the same directory, nor to use the same name as the implementation that is tested.
In order to differentiate between unit, integration, and acceptance tests, build tags can be used. Let’s assume we want to test a Ping
method on the system level. This could be achieved by adding a file ping_test.go
next to ping.go
that adds a build tag as follows:
//go:build system
package ui
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestPing(t *testing.T) {
client := NewClient("https://symflower.com/")
assert.NoError(t, client.Ping())
}
This test can then be executed by issuing the command go test -tags system mypackage
.
You will notice that this command executes the “TestPing” test function, but also every other test function in this package. Why is not only the test file with the “system” tag executed? The reason is that Go also includes files without any build tags.
There are two solutions to this common problem in Go projects:
- a.) Give all test files at least one build tag, e.g. “unit” for unit tests. However, adding such a requirement opens the problem that one can forget to add the tag for the usual testing workflow.
- b.) Use dedicated build tags as well as directories “test-integration” and “test-system” per component for integration and system tests, but let unit tests use Go’s regular conventions. This solution makes it possible to explicitly execute only certain types of tests and reduces the maintenance time for regular unit testing.
Java best practices for unit test naming conventions and test folder structure
The Java unit test naming convention for test classes is to prefix the name of the production class with Test
. Typically Java test files are kept in separate test directories mirroring the package hierarchy of the implementation. Let’s assume a class Plain
is located in the package com.example
with the following file location: src/main/java/com/example/Plain.java
. The associated Java test file is also in a package called “com.example”, but will be located under: src/test/java/com/example/PlainTest.java
.
As for the Java test folder structure: since the exact location for test files is typically not the same over all Java projects, most build tools offer the option to configure the Java test directory that you want to use as the location of test files within a project. Maven, for instance, has as a default location for test files the directory src/test/java
, but also offers the possibility to define other locations. Those are the key practices for naming and locating unit test files that you’ll want to stick to for a clear, logical, and transparent structure.
Configuring Symflower’s test file output
Symflower automatically detects the configuration of your project depending on the programming language, tools, settings and options used for the project.
Default test file location
By default, Symflower puts test files next to the file being tested, postfixing the file name with _symflower_test.go
in Go and SymflowerTest.java
in Java.
For a Java project with the following structure:
└── src
└── main
└── java
└── com
└── example
└── Plain.java
The invocation of symflower
leads to the following output, e.g. a PlainSymflowerTest.java
test file being placed in the appropriate Java test folder:
├── src
│ └── main
│ └── java
│ └── com
│ └── example
│ ├── Plain.java
│ └── PlainSymflowerTest.java
File locations for Maven projects
In case a Maven configuration file pom.xml
is present, Symflower does not use its default location for test files but rather uses the specified source directory for tests.
If no test directory is specified within the provided pom.xml
, then the default output location src/test/java
is used. Resulting in the following project structure:
├── pom.xml
├── src
│ ├── main
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── Plain.java
│ └── test
│ └── java
│ └── com
│ └── example
│ └── PlainSymflowerTest.java
In order to instruct Maven to use another source directory for tests than src/test/java
, the entry testSourceDirectory
needs to be added to the Maven configuration file:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>example</artifactId>
<version>0.0.0</version>
<build>
<testSourceDirectory>src/mytests/java</testSourceDirectory>
</build>
</project>
With this configuration in place, running Symflower results in the tests being put into src/mytests/java
rather than src/test/java
.
Configuring where Symflower should put test files
Besides automatically reusing the existing configuration of your project, Symflower offers two options to define Java test folders e.g. where your test files should be put:
Using a Symflower configuration file
By placing a .symflower/settings.json
file in your project root directory with the following content, you can instruct Symflower to put any generated test files into a sub folder bar/baz
.
{
"TestGeneration": {
"TestsPath": "bar/baz"
}
}
For our running example this changes the output of Symflower to:
├── bar
│ └── baz
│ └── com
│ └── example
│ └── PlainSymflowerTest.java
├── pom.xml
├── src
│ └── main
│ └── java
│ └── com
│ └── example
│ └── Plain.java
├── .symflower
│ └── settings.json
Using Symflower’s command option --tests-path
In order to overwrite the test location for a single invocation of Symflower, you can simply use its command option --tests-path
:
symflower --tests-path="myTestOutputDirectory"
Resulting in the following directory structure:
├── myTestOutputDirectory
│ └── com
│ └── example
│ └── PlainSymflowerTest.java
├── pom.xml
├── src
│ └── main
│ └── java
│ └── com
│ └── example
│ └── Plain.java
The option to configure the location of generated tests was a request in our community issue tracker https://github.com/symflower/symflower/issues. We are eager to hear about more features you would like to see in Symflower. So go ahead and make some suggestions. And make sure to register for our newsletter to not miss out on any upcoming features!