Getting started with Symflower

Install guide for IntelliJ editors

Download the plugin directly from the IntelliJ Marketplace, or follow these steps:

  1. Click File > Settings…
  2. Select “Plugins”. Type “Symflower” into the search field and click “Install”.

Find Symflower on the IntelliJ Marketplace and click Install to start generating unit tests

If you are prompted to restart your IDE or if the plugin is not working after install, please restart your IDE. Check out Symflower’s documentation for a detailed install guide.

Please check out our End-user License Agreement and our Privacy Policy.

Looking for more details? Access our documentation at https://docs.symflower.com/!

Have feedback to share? Open an issue on our community issue tracker or drop us a line at hello@symflower.com.

Quick start guide to Symflower

Symflower adds three key features to your IDE:

We recommend you start with generating test templates:

  1. Open the file you want to analyze
  2. Right-click anywhere on a function
  3. Choose “Symflower: Generate Test Template for Function”

See our tutorial below for a step-by-step example of using Symflower’s features!

Use your IntelliJ IDE's context menu to access Symflower's functions

ℹ️ Test file location
Symflower will extend your already existing test file, or create a new one for the generated test method. The test file's location is determined by the test path defined in your build configuration. If no test path can be found, the test file will be simply placed in the same directory as your production code.

Tutorial example

For this example, we’ll be using a simple copy function. The specification for this task is to create a copy function that copies an array of strings from the parameter from to the parameter to, and then returns to so that callers can use the function in an expression.

Let’s start by defining the function’s API as a stub. Create the directory tutorial and create a file called Copy.java in the directory with the following content:

class Copy {
    static String[] copy(String[] from, String[] to) {
        return to;
    }
}

Per the specification, our first iteration of the function returns to. The copying functionality is not yet implemented. However, since we now have compilable source code, we can already use Symflower to generate our first unit test template that we can use as a starting point for our first unit test as it provides all the necessary boilerplate code.

 1. Generate test template

Place your cursor over the function you want to test in the Copy.java file, right-click in the editor, and select “Symflower: Generate Test Template for Function”.

Congratulations, you just generated your first unit test template with Symflower! The file tree shows you that a new file CopyTest.java has been created with the following content:

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

public class CopyTest {
        @Test
        public void copy() {
                String[] from = { "abc", "abc", "abc" };
                String[] to = { "abc", "abc", "abc" };
                String[] expected = { "abc", "abc", "abc" };
                String[] actual = Copy.copy(from, to);

                assertArrayEquals(expected, actual);
        }
}

This test case represents the simplest unit test for our function: using abc for the parameters from and to which lets the function return abc. Upon execution, we’ll see that this unit test fully covers our source code. You can use this code template as a boilerplate to create further unit tests, filling it in with new values to create new test scenarios.

2. Generate test suite (BETA)

Let’s implement the actual copy functionality of the specification. There are several ways to do this. For now, let’s go with the simplest one where we copy elements one by one. This code is easy to read and understand, and works the same way in most languages:

class Copy {
    static String[] copy(String[] from, String[] to) {
        for (int i = 0; i < from.length; i++) {
            to[i] = from[i];
        }

        return to;
    }
}

Now that we have actual functionality, we can use Symflower to generate a complete test suite to test all possible paths of our code. Right-click on the function’s name and select “Generate Test Suite for Function”. This will yield 5 unit tests.

In your CopyTest.java file, there are now 3 unit tests that fail because the function throws an exception and 2 that pass. Let’s look at the passing tests first to see if it is what we want:

@Test
        public void copy4() {
                String[] from = { null };
                String[] to = { null };
                String[] expected = { null };
                String[] actual = Copy.copy(from, to);

                assertArrayEquals(expected, actual);
        }

We copy from with a single null element into to with a single null element. The expected return argument is an array with a single null as its element. This is definitely according to our specification. Let’s look at the other passing test:

	@Test
	public void copy2() {
		String[] from = {};
		String[] to = null;
		String[] actual = Copy.copy(from, to);

		assertNull(actual);
	}

We copy from with no elements into to which is null and return null. But hold on! Our specification says that we are copying from one array into another. So we need to implement a check to make sure that our parameters are not null. When one of the parameters from or to is null, we found an invalid usage of our API. Java’s IllegalArgumentException is made for cases like this. Let’s add it to our code:

class Copy {
    static String[] copy(String[] from, String[] to) {
        if (from == null || to == null) {
            throw new IllegalArgumentException();
        }

        for (int i = 0; i < from.length; i++) {
            to[i] = from[i];
        }

        return to;
    }
}

Generating new tests with “Symflower: Generate Test Suite for Function” gives us 5 tests once again. The unit test with the empty strings as elements in to and from still exists, but the other unit tests have changed.

There are now 2 unit tests that exercise our new validation logic:

        @Test
        public void copy1() {
                String[] from = null;
                String[] to = null;
                assertThrows(IllegalArgumentException.class, () -> {
                        Copy.copy(from, to);
                });
        }

        @Test
        public void copy2() {
                String[] from = {};
                String[] to = null;
                assertThrows(IllegalArgumentException.class, () -> {
                        Copy.copy(from, to);
                });
        }

We also have a unit test that has empty arrays as parameters and returns an empty array:

        @Test
        public void copy3() {
                String[] from = {};
                String[] to = {};
                String[] expected = {};
                String[] actual = Copy.copy(from, to);

                assertArrayEquals(expected, actual);
        }

Awesome! So far, everything is either according to our specification or throws an IllegalArgumentException. Let’s look at the last generated unit test:

	@Test
	public void copy5() {
		String[] from = { "" };
		String[] to = {};
		// assertThrows(ArrayIndexOutOfBoundsException.class, () -> {
		Copy.copy(from, to);
		// });
	}

Symflower found an out-of-bounds exception since we are copying from an array with 1 element to an array with 0 elements.

What we should do in this case is not defined in the specification: we could either again throw an IllegalArgumentException if the parameters are of different size; we could allocate a new array with the correct size; or we could copy just the elements that fit in the to array. The best solution, of course, is to talk to our team and clarify the specification. We can then adapt the code and use Symflower to make sure that everything works as expected and that all edge cases are covered.

3. Test-backed diagnostics

At this point, you may notice red wiggly lines in your code. Once a test suite is generated, Symflower will highlight any uncaught runtime exceptions. The underlying tests immediately tell you what types of values cause the exception.

Symflower provides test-backed code diagnostics right in your editor, highlighting any runtime exceptions

As you continue working on your implementation, Symflower will automatically maintain the generated unit test suite to keep your code covered with test cases!

Next steps

For further examples, check out Symflower’s documentation, tutorials repository, and examples repository.

Please send us your feedback on Symflower and your experience with the generated tests! If you are missing a feature or found a problem, open an issue on our community issue tracker or drop us a line at hello@symflower.com. Visit our blog and subscribe to the Symflower newsletter to learn about new features, useful guides, and others topics on software development & testing!