0
0
JunitHow-ToBeginner ยท 3 min read

How to Use Dynamic Tests in JUnit 5: Syntax and Examples

In JUnit 5, use @TestFactory to create dynamic tests that generate test cases at runtime. Return a Stream, Collection, or Iterable of DynamicTest objects, each with a display name and executable code block.
๐Ÿ“

Syntax

Dynamic tests in JUnit 5 are created inside methods annotated with @TestFactory. These methods return a Collection, Stream, or Iterable of DynamicTest objects. Each DynamicTest requires a display name and an executable lambda or method reference.

  • @TestFactory: Marks a method that generates dynamic tests.
  • DynamicTest.dynamicTest(String, Executable): Creates a single dynamic test with a name and code.
  • Return type: Must be a Collection, Stream, or Iterable of DynamicTest.
java
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import java.util.stream.Stream;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;

class DynamicTestsExample {
    @TestFactory
    Stream<DynamicTest> dynamicTests() {
        return Stream.of(
            dynamicTest("Test 1", () -> {
                // test code here
            }),
            dynamicTest("Test 2", () -> {
                // test code here
            })
        );
    }
}
๐Ÿ’ป

Example

This example shows a dynamic test factory that tests if numbers are even. It generates tests for numbers 1 to 5, each checking if the number is even. The test names describe the number being tested.

java
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import static org.junit.jupiter.api.Assertions.assertTrue;

class EvenNumberTests {
    @TestFactory
    Stream<DynamicTest> testEvenNumbers() {
        return IntStream.rangeClosed(1, 5)
            .mapToObj(n -> dynamicTest("Is " + n + " even?", () -> {
                assertTrue(n % 2 == 0, n + " is not even");
            }));
    }
}
Output
Test run results: - Is 1 even? FAILED (1 is not even) - Is 2 even? PASSED - Is 3 even? FAILED (3 is not even) - Is 4 even? PASSED - Is 5 even? FAILED (5 is not even)
โš ๏ธ

Common Pitfalls

  • Not annotating the method with @TestFactory will cause tests not to run.
  • Returning a type other than Collection, Stream, or Iterable of DynamicTest causes errors.
  • Using @Test instead of @TestFactory for dynamic tests is incorrect.
  • Dynamic tests must be generated at runtime; returning an empty collection means no tests run.
java
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import java.util.stream.Stream;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;

class WrongDynamicTest {
    // Wrong: Using @Test instead of @TestFactory
    @Test
    Stream<DynamicTest> dynamicTests() {
        return Stream.of(dynamicTest("Test", () -> {}));
    }
}

// Correct way:
import org.junit.jupiter.api.TestFactory;

class CorrectDynamicTest {
    @TestFactory
    Stream<DynamicTest> dynamicTests() {
        return Stream.of(dynamicTest("Test", () -> {}));
    }
}
๐Ÿ“Š

Quick Reference

ConceptDescription
@TestFactoryMarks method that generates dynamic tests
DynamicTest.dynamicTest(name, executable)Creates a single dynamic test
Return typesStream, Collection, or Iterable of DynamicTest
Test namesShould be descriptive for clarity in reports
AssertionsUse standard JUnit assertions inside dynamic tests
โœ…

Key Takeaways

Use @TestFactory to create methods that generate dynamic tests at runtime.
Return a Stream, Collection, or Iterable of DynamicTest objects with descriptive names.
Each DynamicTest needs a display name and executable code (lambda or method reference).
Avoid using @Test annotation for dynamic test methods; it must be @TestFactory.
Dynamic tests help test multiple cases without writing separate test methods.