Configures and runs JUnit 5 (Jupiter) - modern JVM testing platform with annotations (`@Test` / `@ParameterizedTest` / `@RepeatedTest` / `@TestFactory`), lifecycle hooks (`@BeforeAll` / `@BeforeEach` / `@AfterEach` / `@AfterAll`), extension model (`@ExtendWith`), display names (`@DisplayName`), conditional execution (`@EnabledOnOs`, `@EnabledIf`), parallel execution config; integrates with Maven Surefire / Gradle test task / IntelliJ. Use when the user works with Java / Kotlin codebases needing the modern JVM standard.
80
100%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
This plugin was archived by the owner on Oct 11, 2026
Reason: Tile archived: Retired from testland/qa (merged into another skill or removed).
Per junit.org/junit5/docs/current/user-guide:
Three components (released 2017, replacing JUnit 4):
This skill targets JUnit Jupiter (the modern API). For Kotlin-native
tests with similar power but DSL-style, see kotest-tests.
junit-jupiter dependency and enable useJUnitPlatform() (Step 1).@Test method with an assertEquals assertion; run mvn test / ./gradlew test (Step 2).@BeforeEach / @AfterEach) for shared setup and teardown (Step 3).@ParameterizedTest with a source provider (Step 4).@ExtendWith (e.g. MockitoExtension) and annotate display names + conditions (Steps 5-6).junit-platform.properties once tests are independent (Step 7).Maven pom.xml:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>Gradle build.gradle.kts:
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
}
tasks.test {
useJUnitPlatform()
}import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
@Test
void addsTwoNumbers() {
assertEquals(3, Calculator.add(1, 2));
}
}Run: mvn test or ./gradlew test.
Per j5-ug:
class UserServiceTest {
@BeforeAll
static void initAll() { /* once before all */ }
@AfterAll
static void tearDownAll() { /* once after all */ }
@BeforeEach
void init() { /* before each test */ }
@AfterEach
void tearDown() { /* after each test */ }
@Test
void test1() { ... }
@Test
void test2() { ... }
}import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;
class ParametrizedTest {
@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 5, 8})
void numbersInFibonacci(int n) {
assertTrue(isFibonacci(n));
}
@ParameterizedTest
@CsvSource({
"1, 2, 3",
"0, 0, 0",
"-1, 1, 0",
})
void addCases(int a, int b, int expected) {
assertEquals(expected, Calculator.add(a, b));
}
@ParameterizedTest
@MethodSource("addProvider")
void addsViaMethodSource(int a, int b, int expected) {
assertEquals(expected, Calculator.add(a, b));
}
static Stream<Arguments> addProvider() {
return Stream.of(
Arguments.of(1, 2, 3),
Arguments.of(0, 0, 0)
);
}
}Source providers: @ValueSource, @CsvSource, @CsvFileSource,
@MethodSource, @EnumSource, @ArgumentsSource.
@ExtendWith)JUnit 5's extension model (replaces JUnit 4's @Rule /
@RunWith):
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository repo;
@InjectMocks
private UserService service;
@Test
void createsUser() {
when(repo.save(any())).thenReturn(new User(1, "Alice"));
User u = service.create("Alice");
assertEquals(1, u.getId());
}
}Common extensions: MockitoExtension, SpringExtension (Spring),
SystemStubsExtension (env vars / system properties),
TempDirectory.
@DisplayName("User service")
class UserServiceTest {
@Test
@DisplayName("creates a user with email lowercased")
void createsUserWithLowercaseEmail() { ... }
@Test
@EnabledOnOs(OS.LINUX)
void linuxOnlyTest() { ... }
@Test
@EnabledIfEnvironmentVariable(named = "INTEGRATION", matches = "true")
void integrationOnly() { ... }
@Test
@Disabled("Re-enable after fixing JIRA-1234")
void temporarilyDisabled() { ... }
}Enable in junit-platform.properties:
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.config.strategy = dynamicPer-test override:
@Execution(ExecutionMode.SAME_THREAD)
class TestNotParallelizable { ... }Wire JaCoCo coverage (Maven / Gradle) and CI reporting (GitHub Actions + Codecov; Surefire emits JUnit XML for junit-xml-analysis in the qa-test-reporting plugin) per references/coverage-and-ci.md.
Testing Calculator.add across many inputs:
org.junit.jupiter:junit-jupiter:5.11.0 (test scope) and enable useJUnitPlatform().@Test methods with one @ParameterizedTest + @CsvSource({"1, 2, 3", "0, 0, 0", "-1, 1, 0"}) taking (int a, int b, int expected).assertEquals(expected, Calculator.add(a, b)) - each row reports as its own test../gradlew test: three cases execute; the -1, 1, 0 row fails, isolating the sign bug while the others stay green.jacocoTestReport (Step 8) to confirm the add branch is now covered.| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Mix JUnit 4 + JUnit 5 in same project | Two runners, confusing | Pick Jupiter; use Vintage only for migration |
@Test from org.junit.Test (JUnit 4) | Doesn't run with Jupiter runner | Import org.junit.jupiter.api.Test (Step 2) |
| Skip parallel-execution config | Slow test suite at scale | Enable parallel.enabled (Step 7) |
Use @Disabled without ticket reference | Forgotten disabled tests | Always include reason + JIRA link (Step 6) |
Generic assertTrue(x.equals(y)) | Loses diff in failure | assertEquals(x, y) |
kotest-tests,
spock-tests,
testng-tests,
scalatest - sister toolstest-code-conventions - test code hygiene