Generating smart test templates
Generate smart test templates with all the necessary boilerplate code to reduce the time and effort costs unit and integration testing. Generated smart test templates contain all the necessary function calls, object initializations, asserts, imports, and annotations, leaving you in charge of defining the actual values for testing.
Usage
Open the file you want to analyze and choose any of the following options to trigger the generation of smart test templates:
Code lens
Click the "create test" code lens above any function to generate test templates for that function:
Context menu
Right-click into a function and select "Symflower: Generate Test Template for Function" from the context menu:
Keyboard shortcut
Define a keyboard shortcut to trigger Symflower's smart test template generation. Position your cursor within a function and hit your specified keybinding:
Command palette
Position your cursor into a function. Open the command palette of your editor and start typing "Symflower". Select the entry "Symflower: Generate Test Template for Function" (or use "Symflower: Generate Test Templates for File" if you want to generate test templates for the entire file):
Symflower generates a new test method either by extending an already existing test file or by creating a new one. The chosen file location is determined using the test path defined in your build configuration. If none can be found, the test file is placed in the same directory as your production code.
Details
Symflower currently supports the build systems Maven and Gradle for automatic test path detection. The plugin supports the generation of JUnit 4 and JUnit 5 test cases. Have Symflower automatically detect the framework you are using, or select the framework manually in Symflower's configuration options.
Tutorial
This tutorial takes the example of a simple implementation of a class that stores triangles. Besides storing the length of each side of the triangle, the application should also categorize the triangle in question:
- Equilateral: all sides are the same length
- Isosceles: two sides have the same length
- Scalene: none of the sides are equal in length
Step 1: Tutorial example
For this geometric triangle class, we'll need three member variables for the three triangle sides, a constructor, and the available triangle types. Let's also a possible implementation of the getType
function.
Copy the following code into a file called Triangle.java
:
public class Triangle {
private int sideA;
private int sideB;
private int sideC;
public Triangle(int sideA, int sideB, int sideC) {
this.sideA = sideA;
this.sideB = sideB;
this.sideC = sideC;
}
public TriangleType getType() {
// Each side needs to be greater than 0
if (sideA <= 0 || sideB <= 0 || sideC <= 0) {
return TriangleType.invalid;
}
// Two sides need to be bigger than the third
if(this.sideA + this.sideB < sideC || this.sideB + this.sideC < this.sideA || this.sideA + this.sideC < this.sideB){
return TriangleType.invalid;
}
if (this.sideA == this.sideB && this.sideB == this.sideC) {
return TriangleType.equilateral;
}
if (this.sideA == this.sideB || this.sideB == this.sideC || this.sideA == this.sideC) {
return TriangleType.isosceles;
}
return TriangleType.scalene;
}
}
enum TriangleType {
equilateral,
isosceles,
scalene,
invalid
}
Step 2: Generate test template
Use any of the usage options above to generate smart test templates. A new test file TriangleTest.java
will be created with the following contents:
- JUnit 4
- JUnit 5
import org.junit.*;
import static org.junit.Assert.*;
public class TriangleTest {
@Test
public void Triangle() {
int sideA = 123;
int sideB = 123;
int sideC = 123;
Triangle expected = new Triangle(123, 123, 123);
Triangle actual = new Triangle(sideA, sideB, sideC);
assertEquals(expected, actual);
}
}
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
public class TriangleTest {
@Test
public void Triangle() {
int sideA = 123;
int sideB = 123;
int sideC = 123;
Triangle expected = new Triangle(123, 123, 123);
Triangle actual = new Triangle(sideA, sideB, sideC);
assertEquals(expected, actual);
}
}
Step 3: Name test case and update values
Next up, choose an appropriate name for your test case and update the test values as you see fit. Your cursor will be automatically moved to the right location to assign a new name to your test case. Any subsequently generated smart test templates will be automatically added to the same test file. Add the desired tests to your test file,
Scenarios
Generate imports
Upon test template generation, all the required imports will be automatically added to the generated test file.
The following example code relies on the class Triangle
which resides in another package.
package com.symflower.example;
import com.symflower.shapes.Triangle;
import com.symflower.shapes.TriangleType;
public class Utils {
Triangle initTriangle() {...}
...
}
In the generated test template file below, the necessary import for Triangle
and the required dependencies for unit testing with JUnit 5 have been added automatically:
- JUnit 4
- JUnit 5
package com.symflower.example;
import org.junit.*;
import static org.junit.Assert.*;
import com.symflower.shapes.TriangleType;
import com.symflower.shapes.Triangle;
public class UtilsTest {
...
}
package com.symflower.example;
import com.symflower.shapes.Triangle;
import com.symflower.shapes.TriangleType;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
public class UtilsTest {
...
}
Default template values
Symflower's smart test templates initialize variables with a predefined value. The following table lists the default value used per type:
Type | Template Value |
---|---|
byte | 123 |
short | 123 |
int | 123 |
long | 123L |
float | 123.4F |
double | 123.4D |
String | "abc" |
char | 'a' |
boolean | true |
For complex data types, Symflower's smart test templates aim to choose the simplest constructor for initialization. For enums, the template value is set to the first encountered enumeration constant.
Let's take a look at a concrete example to see how variables are typically initialized with Symflower's smart test templates. The method under test initTriangle
receives a TriangleType
and returns an initialized Triangle
:
package com.symflower.example;
import com.symflower.shapes.Triangle;
import com.symflower.shapes.TriangleType;
public class Utils {
static Triangle initTriangle(TriangleType t) {...}
}
The generated test template then looks as follows:
- JUnit 4
- JUnit 5
package com.symflower.example;
import org.junit.*;
import static org.junit.Assert.*;
import com.symflower.shapes.TriangleType;
import com.symflower.shapes.Triangle;
public class UtilsTest {
@Test
public void initTriangle() {
TriangleType t = TriangleType.equilateral;
Triangle expected = new Triangle(123, 123, 123);
Triangle actual = Utils.initTriangle(t);
assertEquals(expected, actual);
}
}
package com.symflower.example;
import com.symflower.shapes.Triangle;
import com.symflower.shapes.TriangleType;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
public class UtilsTest {
@Test
public void initTriangle() {
TriangleType t = TriangleType.equilateral;
Triangle expected = new Triangle(123, 123, 123);
Triangle actual = Utils.initTriangle(t);
assertEquals(expected, actual);
}
}
Note that the required enum t
is initialized with the enum value TriangleType.equilateral
and the expected Triangle
by calling the only provided constructor new Triangle(123, 123, 123)
.
Generate assertions
The generated assertions depend on the recommended assertion function per type. Most often, assertEquals
is used to compare the results of a function. In the case of a returned array type, the function assertArrayEquals
is used instead:
package com.symflower.example;
import com.symflower.shapes.Triangle;
import com.symflower.shapes.TriangleType;
public class Utils {
...
static Triangle[] getTriangles(){
...
}
}
Here's what the generated test looks like:
- JUnit 4
- JUnit 5
package com.symflower.example;
import com.symflower.shapes.Triangle;
import org.junit.*;
import static org.junit.Assert.*;
public class UtilsTest {
@Test
public void getTriangles() {
Triangle[] expected = { new Triangle(123, 123, 123), new Triangle(123, 123, 123), new Triangle(123, 123, 123) };
Triangle[] actual = Utils.getTriangles();
assertArrayEquals(expected, actual);
}
}
package com.symflower.example;
import com.symflower.shapes.Triangle;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
public class UtilsTest {
@Test
public void getTriangles() {
Triangle[] expected = { new Triangle(123, 123, 123), new Triangle(123, 123, 123), new Triangle(123, 123, 123) };
Triangle[] actual = Utils.getTriangles();
assertArrayEquals(expected, actual);
}
}
Symflower supports Spring Boot offering more boilerplate code specific to Spring Boot tests.